diff --git a/src/TNL/Solvers/LinearSolverTypeResolver.h b/src/TNL/Solvers/LinearSolverTypeResolver.h
index 18bf08039960a3929dfb07d651ce8b8f10870841..5615ea7077bad28229b21b8a45c9eb297c5aa3d6 100644
--- a/src/TNL/Solvers/LinearSolverTypeResolver.h
+++ b/src/TNL/Solvers/LinearSolverTypeResolver.h
@@ -12,6 +12,8 @@
 
 #pragma once
 
+#include <vector>
+#include <string>
 #include <memory>
 
 #include <TNL/Solvers/Linear/SOR.h>
@@ -28,54 +30,89 @@
 namespace TNL {
 namespace Solvers {
 
+inline std::vector<std::string>
+getLinearSolverOptions()
+{
+   return {
+      "sor",
+      "cg",
+      "bicgstab",
+      "bicgstabl",
+      "gmres",
+      "tfqmr"
+#ifdef HAVE_UMFPACK
+      , "umfpack"
+#endif
+   };
+}
+
+inline std::vector<std::string>
+getPreconditionerOptions()
+{
+   return {
+      "none",
+      "diagonal",
+      "ilu0",
+      "ilut"
+   };
+}
+
 template< typename MatrixType >
 std::shared_ptr< Linear::LinearSolver< MatrixType > >
-getLinearSolver( const Config::ParameterContainer& parameters )
+getLinearSolver( std::string name )
 {
-   const String& discreteSolver = parameters.getParameter< String >( "discrete-solver" );
-
-   if( discreteSolver == "sor" )
+   if( name == "sor" )
       return std::make_shared< Linear::SOR< MatrixType > >();
-   if( discreteSolver == "cg" )
+   if( name == "cg" )
       return std::make_shared< Linear::CG< MatrixType > >();
-   if( discreteSolver == "bicgstab" )
+   if( name == "bicgstab" )
       return std::make_shared< Linear::BICGStab< MatrixType > >();
-   if( discreteSolver == "bicgstabl" )
+   if( name == "bicgstabl" )
       return std::make_shared< Linear::BICGStabL< MatrixType > >();
-   if( discreteSolver == "gmres" )
+   if( name == "gmres" )
       return std::make_shared< Linear::GMRES< MatrixType > >();
-   if( discreteSolver == "tfqmr" )
+   if( name == "tfqmr" )
       return std::make_shared< Linear::TFQMR< MatrixType > >();
 #ifdef HAVE_UMFPACK
    if( discreteSolver == "umfpack" )
       return std::make_shared< Linear::UmfpackWrapper< MatrixType > >();
 #endif
 
-   std::cerr << "Unknown semi-implicit discrete solver " << discreteSolver << ". It can be only: sor, cg, bicgstab, bicgstabl, gmres, tfqmr";
-#ifdef HAVE_UMFPACK
-   std::cerr << ", umfpack"
-#endif
-   std::cerr << "." << std::endl;
+   std::string options;
+   for( auto o : getLinearSolverOptions() )
+      if( options.empty() )
+         options += o;
+      else
+         options += ", " + o;
+
+   std::cerr << "Unknown semi-implicit discrete solver " << name << ". It can be only: " << options << "." << std::endl;
 
    return nullptr;
 }
 
 template< typename MatrixType >
 std::shared_ptr< Linear::Preconditioners::Preconditioner< MatrixType > >
-getPreconditioner( const Config::ParameterContainer& parameters )
+getPreconditioner( std::string name )
 {
-   const String& preconditioner = parameters.getParameter< String >( "preconditioner" );
 
-   if( preconditioner == "none" )
+   if( name == "none" )
       return nullptr;
-   if( preconditioner == "diagonal" )
+   if( name == "diagonal" )
       return std::make_shared< Linear::Preconditioners::Diagonal< MatrixType > >();
-   if( preconditioner == "ilu0" )
+   if( name == "ilu0" )
       return std::make_shared< Linear::Preconditioners::ILU0< MatrixType > >();
-   if( preconditioner == "ilut" )
+   if( name == "ilut" )
       return std::make_shared< Linear::Preconditioners::ILUT< MatrixType > >();
 
-   std::cerr << "Unknown preconditioner " << preconditioner << ". It can be only: none, diagonal, ilu0, ilut." << std::endl;
+   std::string options;
+   for( auto o : getPreconditionerOptions() )
+      if( options.empty() )
+         options += o;
+      else
+         options += ", " + o;
+
+   std::cerr << "Unknown preconditioner " << name << ". It can be only: " << options << "." << std::endl;
+
    return nullptr;
 }
 
diff --git a/src/TNL/Solvers/PDE/SemiImplicitTimeStepper_impl.h b/src/TNL/Solvers/PDE/SemiImplicitTimeStepper_impl.h
index 5faa7902e179781e413dca4715d73e06e5dffdbb..3e8d106b272cf66bf2ed867d0a0943d0b47d8944 100644
--- a/src/TNL/Solvers/PDE/SemiImplicitTimeStepper_impl.h
+++ b/src/TNL/Solvers/PDE/SemiImplicitTimeStepper_impl.h
@@ -33,14 +33,16 @@ setup( const Config::ParameterContainer& parameters,
        const String& prefix )
 {
    // set up the linear solver
-   linearSystemSolver = getLinearSolver< MatrixType >( parameters );
+   const String& discreteSolver = parameters.getParameter< String >( prefix + "discrete-solver" );
+   linearSystemSolver = getLinearSolver< MatrixType >( discreteSolver );
    if( ! linearSystemSolver )
       return false;
    if( ! linearSystemSolver->setup( parameters ) )
       return false;
 
    // set up the preconditioner
-   preconditioner = getPreconditioner< MatrixType >( parameters );
+   const String& preconditionerName = parameters.getParameter< String >( prefix + "preconditioner" );
+   preconditioner = getPreconditioner< MatrixType >( preconditionerName );
    if( preconditioner ) {
       linearSystemSolver->setPreconditioner( preconditioner );
       if( ! preconditioner->setup( parameters ) )
diff --git a/src/TNL/Solvers/SolverConfig_impl.h b/src/TNL/Solvers/SolverConfig_impl.h
index e5673d5c1ed45ea9a28f8615cd4f099284bb8875..9d3515157feeac58a73b56353274524a56f6ec1a 100644
--- a/src/TNL/Solvers/SolverConfig_impl.h
+++ b/src/TNL/Solvers/SolverConfig_impl.h
@@ -15,16 +15,7 @@
 #include <TNL/Solvers/DummyProblem.h>
 #include <TNL/Solvers/PDE/ExplicitTimeStepper.h>
 #include <TNL/Solvers/PDE/TimeDependentPDESolver.h>
-#include <TNL/Solvers/Linear/SOR.h>
-#include <TNL/Solvers/Linear/CG.h>
-#include <TNL/Solvers/Linear/BICGStab.h>
-#include <TNL/Solvers/Linear/BICGStabL.h>
-#include <TNL/Solvers/Linear/GMRES.h>
-#include <TNL/Solvers/Linear/TFQMR.h>
-#include <TNL/Solvers/Linear/UmfpackWrapper.h>
-#include <TNL/Solvers/Linear/Preconditioners/Diagonal.h>
-#include <TNL/Solvers/Linear/Preconditioners/ILU0.h>
-#include <TNL/Solvers/Linear/Preconditioners/ILUT.h>
+#include <TNL/Solvers/LinearSolverTypeResolver.h>
 #include <TNL/Matrices/CSR.h>
 #include <TNL/Meshes/DistributedMeshes/DistributedGrid.h>
 
@@ -124,23 +115,11 @@ bool SolverConfig< ConfigTag, ProblemConfig >::configSetup( Config::ConfigDescri
    }
    if( ConfigTagTimeDiscretisation< ConfigTag, SemiImplicitTimeDiscretisationTag >::enabled )
    {
-      config.addEntryEnum( "cg" );
-      config.addEntryEnum( "bicgstab" );
-      config.addEntryEnum( "bicgstabl" );
-      config.addEntryEnum( "gmres" );
-      config.addEntryEnum( "tfqmr" );
-      config.addEntryEnum( "sor" );
-#ifdef HAVE_UMFPACK
-      config.addEntryEnum( "umfpack" );
-#endif
+      for( auto o : getLinearSolverOptions() )
+         config.addEntryEnum( String( o ) );
       config.addEntry< String >( "preconditioner", "The preconditioner for the discrete solver:", "none" );
-      config.addEntryEnum( "none" );
-      config.addEntryEnum( "diagonal" );
-   // TODO: implement parallel ILU or device-dependent build config tags for preconditioners
-#ifndef HAVE_CUDA
-      config.addEntryEnum( "ilu0" );
-      config.addEntryEnum( "ilut" );
-#endif
+      for( auto o : getPreconditionerOptions() )
+         config.addEntryEnum( String( o ) );
    }
    if( ConfigTagTimeDiscretisation< ConfigTag, ExplicitTimeDiscretisationTag >::enabled ||
        ConfigTagTimeDiscretisation< ConfigTag, SemiImplicitTimeDiscretisationTag >::enabled )