diff --git a/demos/hello_wolf/hello_wolf_autoconf.cpp b/demos/hello_wolf/hello_wolf_autoconf.cpp
index e643c6f13c8c94d3e0085eeed627658cc01856c8..094b17429bb03774d83c780501239686f164eb4b 100644
--- a/demos/hello_wolf/hello_wolf_autoconf.cpp
+++ b/demos/hello_wolf/hello_wolf_autoconf.cpp
@@ -111,22 +111,17 @@ int main()
     std::string config_file = "demos/hello_wolf/yaml/hello_wolf_config.yaml";
     std::string wolf_path   = _WOLF_CODE_DIR;
 
-    // parse file into params server: each param will be retrievable from this params server:
+    // parse file into params node
     yaml_schema_cpp::YamlServer server({wolf_path}, wolf_path + "/" + config_file);
-    if (not server.applySchema("Problem2d"))
-    {
-        WOLF_ERROR(server.getLog());
-        return 1;
-    }
-    // Wolf problem: automatically build the left branch of the wolf tree from the contents of the params server:
-    ProblemPtr problem = Problem::autoSetup(server.getNode());
+
+    // Wolf problem: automatically build the left branch of the wolf tree from the contents of the yaml node
+    ProblemPtr problem = Problem::autoSetup(server.getNode(), {wolf_path});
 
     // Print problem to see its status before processing any sensor data
     problem->print(4, 0, 1, 0);
 
     // Solver. Configure a Ceres solver
-    SolverManagerPtr ceres =
-        FactorySolverNode::create("SolverCeres", problem, server.getNode()["solver"], {wolf_path});
+    SolverManagerPtr ceres = SolverManager::autoSetup(problem, server.getNode()["solver"], {wolf_path});
     if (not ceres)
     {
         WOLF_ERROR("Couldn't load or validate the yaml file for the solver");
@@ -229,7 +224,7 @@ int main()
 
     // SOLVE with exact initial guess
     WOLF_INFO("======== SOLVE PROBLEM WITH EXACT PRIORS =======")
-    std::string report = ceres->solve(SolverManager::ReportVerbosity::FULL);
+    std::string report = ceres->solve(ReportVerbosity::FULL);
     WOLF_INFO(report);  // should show a very low iteration number (possibly 1)
     problem->print(1, 0, 1, 0);
 
@@ -240,13 +235,13 @@ int main()
 
     // SOLVE again
     WOLF_INFO("======== SOLVE PROBLEM WITH PERTURBED PRIORS =======")
-    report = ceres->solve(SolverManager::ReportVerbosity::FULL);
+    report = ceres->solve(ReportVerbosity::FULL);
     WOLF_INFO(report);  // should show a very high iteration number (more than 10, or than 100!)
     problem->print(1, 0, 1, 0);
 
     // GET COVARIANCES of all states
     WOLF_INFO("======== COVARIANCES OF SOLVED PROBLEM =======")
-    ceres->computeCovariances(SolverManager::CovarianceBlocksToBeComputed::ALL_MARGINALS);
+    ceres->computeCovariances(CovarianceBlocksToBeComputed::ALL_MARGINALS);
     for (auto& kf_pair : problem->getTrajectory()->getFrameMap())
     {
         Eigen::MatrixXd cov;
diff --git a/demos/hello_wolf/yaml/hello_wolf_config.yaml b/demos/hello_wolf/yaml/hello_wolf_config.yaml
index a59401409a93dc6a16c47d53c44192f08232a35f..7f718f169bf02cdf17f701d3ae7de9fac9fc3c5d 100644
--- a/demos/hello_wolf/yaml/hello_wolf_config.yaml
+++ b/demos/hello_wolf/yaml/hello_wolf_config.yaml
@@ -19,6 +19,8 @@ problem:
     type: "none"
 
 solver:
+  type: SolverCeres
+  plugin: core
   max_num_iterations: 100
   verbose: 0
   period: 0.2
@@ -27,9 +29,9 @@ solver:
   compute_cov: false
   minimizer: LEVENBERG_MARQUARDT
   use_nonmonotonic_steps: false         # only for LEVENBERG_MARQUARDT and DOGLEG
-  parameter_tolerance: 0.000001
-  function_tolerance: 0.000001
-  gradient_tolerance: 0.0000000001
+  parameter_tolerance: 1e-6
+  function_tolerance: 1e-6
+  gradient_tolerance: 1e-10
   
 sensors:
   
diff --git a/include/core/problem/problem.h b/include/core/problem/problem.h
index 307e58ab5d010ff3082c1c83d27a0cd6e4a8d8a1..9f329f3177ec4267bbf33144f06e04b3c3b41436 100644
--- a/include/core/problem/problem.h
+++ b/include/core/problem/problem.h
@@ -105,8 +105,11 @@ class Problem : public std::enable_shared_from_this<Problem>
                              const TypeComposite& _frame_structure = {},
                              LoaderPtr            _loader          = nullptr);  // USE THIS AS A CONSTRUCTOR!
     static ProblemPtr autoSetup(const std::string&       _input_yaml_file,
-                                std::vector<std::string> _primary_schema_folders = {});
-    static ProblemPtr autoSetup(YAML::Node _param_node, LoaderPtr _loader = nullptr);
+                                std::vector<std::string> _primary_schema_folders = {},
+                                LoaderPtr                _loader                 = nullptr);
+    static ProblemPtr autoSetup(YAML::Node               _param_node,
+                                std::vector<std::string> _primary_schema_folders = {},
+                                LoaderPtr                _loader                 = nullptr);
     virtual ~Problem();
 
     // Properties -----------------------------------------
diff --git a/include/core/solver/solver_manager.h b/include/core/solver/solver_manager.h
index 664231fd1ee366b60da32c2bdc44fe97716558f3..ab6e04e72fa59f28777e32c9fb413ac054fb7a4a 100644
--- a/include/core/solver/solver_manager.h
+++ b/include/core/solver/solver_manager.h
@@ -33,13 +33,13 @@ WOLF_PTR_TYPEDEFS(SolverManager)
 /*
  * Macro for defining Autoconf solver creator for WOLF's high level API.
  *
- * Place a call to this macro inside your class declaration (in the solver_manager_class.h file),
+ * Place a call to this macro inside your class declaration (in the solver_class.h file),
  * preferably just after the constructors.
  *
- * In order to use this macro, the derived solver manager class, SolverManagerClass,
+ * In order to use this macro, the derived solver manager class, SolverClass,
  * must have a constructor available with the API:
  *
- *   SolverManagerClass(const ProblemPtr& wolf_problem,
+ *   SolverClass(const ProblemPtr& wolf_problem,
  *                      const YAML::Node _params);
  */
 #define WOLF_SOLVER_CREATE(SolverClass)                                                                               \
@@ -79,9 +79,6 @@ class SolverManager
 {
   public:
     /** \brief Enumeration of covariance blocks to be computed
-     *
-     * Enumeration of covariance blocks to be computed
-     *
      */
     enum class CovarianceBlocksToBeComputed : std::size_t
     {
@@ -94,8 +91,7 @@ class SolverManager
         GAUSS_TUCAN_ONLY_POSITION = 5   ///< GAUSS: last frame P and T
     };
 
-    /**
-     * \brief Enumeration for the verbosity of the solver report.
+    /** \brief Enumeration for the verbosity of the solver report.
      */
     enum class ReportVerbosity : std::size_t
     {
@@ -134,6 +130,16 @@ class SolverManager
      */
     SolverManager(const ProblemPtr& _problem, const YAML::Node& _params);
 
+    static SolverManagerPtr autoSetup(const ProblemPtr&        _problem,
+                                      const std::string&       _input_yaml_file,
+                                      std::vector<std::string> _primary_schema_folders = {},
+                                      LoaderPtr                _loader                 = nullptr);
+
+    static SolverManagerPtr autoSetup(const ProblemPtr&        _problem,
+                                      YAML::Node               _param_node,
+                                      std::vector<std::string> _primary_schema_folders = {},
+                                      LoaderPtr                _loader                 = nullptr);
+
     virtual ~SolverManager();
 
     /**
@@ -241,11 +247,11 @@ class SolverManager
 
   protected:
     // PARAMS
-    double                                      period_;
-    SolverManager::ReportVerbosity              verbose_;
-    bool                                        compute_cov_;
-    SolverManager::CovarianceBlocksToBeComputed cov_enum_;
-    double                                      cov_period_;
+    double                       period_;
+    ReportVerbosity              verbose_;
+    bool                         compute_cov_;
+    CovarianceBlocksToBeComputed cov_enum_;
+    double                       cov_period_;
 };
 
 }  // namespace wolf
diff --git a/schema/problem/Problem.schema b/schema/problem/Problem.schema
index f681a495b1e7a73efed41159bdaf6d7c4e28b9b1..71d7f9b6930adf84fe83cee67b4cb4830aeae838 100644
--- a/schema/problem/Problem.schema
+++ b/schema/problem/Problem.schema
@@ -5,7 +5,7 @@ problem:
     _mandatory: true
     _doc: Tree manager parameters
   dimension:
-    _type: int
+    _type: unsigned int
     _mandatory: true
     _options: [2, 3]
     _doc: "Dimension of the problem. '2' for 2D or '3' for 3D"
diff --git a/schema/problem/Problem2d.schema b/schema/problem/Problem2d.schema
index ab42adc11bdc80aec1ccd2b11b36affa22709a44..51ce8f238a9ff051d848ee55ddda3f49c4bc415e 100644
--- a/schema/problem/Problem2d.schema
+++ b/schema/problem/Problem2d.schema
@@ -15,7 +15,7 @@ problem:
       _doc: "specification for the first frame linear velocity state"
       
   dimension:
-    _type: int
+    _type: unsigned int
     _mandatory: true
     _options: [2]
     _doc: "Dimension of the problem: '2' for 2D"
\ No newline at end of file
diff --git a/schema/problem/Problem3d.schema b/schema/problem/Problem3d.schema
index 3ef63833fd716f972cf9229777970c1d14d0e639..6f6dffd3fbe40d581abb219782532831121aa610 100644
--- a/schema/problem/Problem3d.schema
+++ b/schema/problem/Problem3d.schema
@@ -15,7 +15,7 @@ problem:
       _doc: "specification for the first frame linear velocity state"
       
   dimension:
-    _type: int
+    _type: unsigned int
     _mandatory: true
     _options: [3]
     _doc: "Dimension of the problem: '3' for 3D"
\ No newline at end of file
diff --git a/src/problem/problem.cpp b/src/problem/problem.cpp
index 766edef8ff256e05c63337a4b6ec537579eee771..fdf17296a82765151cce784bc6b5fd8034ab3549 100644
--- a/src/problem/problem.cpp
+++ b/src/problem/problem.cpp
@@ -81,17 +81,28 @@ ProblemPtr Problem::create(SizeEigen _dim, const TypeComposite& _frame_types, Lo
     return p->shared_from_this();
 }
 
-ProblemPtr Problem::autoSetup(const std::string& _input_yaml_file, std::vector<std::string> _schema_folders)
+ProblemPtr Problem::autoSetup(const std::string& _input_yaml_file, std::vector<std::string> _schema_folders, LoaderPtr _loader)
 {
-    // Create YAML server
+    // Load YAML node (yaml schema server used to flatten "follows")
     WOLF_DEBUG("Loading YAML file...");
     yaml_schema_cpp::YamlServer server = yaml_schema_cpp::YamlServer(_schema_folders, _input_yaml_file);
-    // YAML::Node                  params_node = server.getNode();
+
+    // Call autoSetup via YAML node
+    return Problem::autoSetup(server.getNode(), _schema_folders, _loader);
+}
+
+ProblemPtr Problem::autoSetup(YAML::Node _param_node, std::vector<std::string> _schema_folders, LoaderPtr _loader)
+{
+    // VALIDATION ===============================================================================
+    // Create YAML server
+    yaml_schema_cpp::YamlServer server = yaml_schema_cpp::YamlServer(_schema_folders);
+    server.setYaml(_param_node);
 
     // SCHEMA FOLDERS (optional _schema_folders specify folders where to search schemas before installed ones)
     // Search and load plugins to get the installed schema folders registered
-    auto loader = std::make_shared<Loader>();
-    searchAndLoadPlugins(server.getNode(), loader);
+    if (not _loader)
+        _loader = std::make_shared<Loader>();
+    searchAndLoadPlugins(server.getNode(), _loader);
 
     // Add the installed schema folders after optional input folders
     server.addFolderSchema(FolderRegistry::getRegisteredFolders());
@@ -103,7 +114,7 @@ ProblemPtr Problem::autoSetup(const std::string& _input_yaml_file, std::vector<s
         WOLF_ERROR(server.getLog());
         return nullptr;
     }
-    // Validate against schema of specific dimension
+    // Validate against specific schema 2D or 3D
     bool is2D = server.getNode()["problem"]["dimension"].as<int>() == 2;
     if (not server.applySchema(is2D ? "Problem2d.schema" : "Problem3d.schema"))
     {
@@ -115,12 +126,6 @@ ProblemPtr Problem::autoSetup(const std::string& _input_yaml_file, std::vector<s
                "! Node after validation:\n",
                server.getNode());
 
-    // Get param node
-    return Problem::autoSetup(server.getNode(), loader);
-}
-
-ProblemPtr Problem::autoSetup(YAML::Node _param_node, LoaderPtr _loader)
-{
     // PROBLEM ===============================================================================
     // dimension
     WOLF_DEBUG("Loading problem parameters...");
@@ -1295,7 +1300,7 @@ void Problem::perturb(double amplitude)
 
 void Problem::transform(const VectorComposite& _transformation)
 {
-    std::lock_guard<std::mutex> lock_transform(mut_transform_);  // Protect especially from SolverManager::update()
+    std::lock_guard<std::mutex> lock_transform(mut_transform_);  // Protect especially from SolverBase::update()
 
     transformation_ = _transformation;
     transformed_.store(true);
diff --git a/src/solver/solver_manager.cpp b/src/solver/solver_manager.cpp
index bdb62f31eb9db6685ebf65363c658d05cbb64964..ebd0274d5459ad66d7be6a1852b90fa508e0e224 100644
--- a/src/solver/solver_manager.cpp
+++ b/src/solver/solver_manager.cpp
@@ -22,6 +22,7 @@
 #include "core/trajectory/trajectory_base.h"
 #include "core/map/map_base.h"
 #include "core/landmark/landmark_base.h"
+#include "core/utils/loader_utils.h"
 
 namespace wolf
 {
@@ -44,17 +45,69 @@ SolverManager::SolverManager(const ProblemPtr& _problem, const YAML::Node& _para
     assert(_problem != nullptr && "Passed a nullptr ProblemPtr.");
 
     period_      = _params["period"].as<double>();
-    verbose_     = (SolverManager::ReportVerbosity)_params["verbose"].as<int>();
+    verbose_     = (ReportVerbosity)_params["verbose"].as<int>();
     compute_cov_ = _params["compute_cov"].as<bool>();
     if (compute_cov_)
     {
-        cov_enum_   = (SolverManager::CovarianceBlocksToBeComputed)_params["cov_enum"].as<int>();
+        cov_enum_   = (CovarianceBlocksToBeComputed)_params["cov_enum"].as<int>();
         cov_period_ = _params["cov_period"].as<double>();
     }
 }
 
 SolverManager::~SolverManager() {}
 
+SolverManagerPtr SolverManager::autoSetup(const ProblemPtr&        _problem,
+                                          const std::string&       _input_yaml_file,
+                                          std::vector<std::string> _schema_folders,
+                                          LoaderPtr                _loader)
+{
+    // Load YAML node (yaml schema server used to flatten "follows")
+    WOLF_DEBUG("Loading YAML file...");
+    yaml_schema_cpp::YamlServer server = yaml_schema_cpp::YamlServer(_schema_folders, _input_yaml_file);
+
+    // Call autoSetup via YAML node
+    return SolverManager::autoSetup(_problem, server.getNode(), _schema_folders, _loader);
+}
+
+SolverManagerPtr SolverManager::autoSetup(const ProblemPtr&        _problem,
+                                          YAML::Node               _param_node,
+                                          std::vector<std::string> _schema_folders,
+                                          LoaderPtr                _loader)
+{
+    // VALIDATION ===============================================================================
+    // Create YAML server
+    yaml_schema_cpp::YamlServer server = yaml_schema_cpp::YamlServer(_schema_folders);
+    server.setYaml(_param_node);
+
+    // SCHEMA FOLDERS (optional _schema_folders specify folders where to search schemas before installed ones)
+    // Search and load plugins to get the installed schema folders registered
+    if (not _loader) _loader = std::make_shared<Loader>();
+    searchAndLoadPlugins(server.getNode(), _loader);
+
+    // Add the installed schema folders after optional input folders
+    server.addFolderSchema(FolderRegistry::getRegisteredFolders());
+
+    // Validate against TypeAndPlugin (check if it has 'type' and 'plugin')
+    // NOTE: Validation with the correponding schema is done in the creator
+    if (not server.applySchema("TypeAndPlugin"))
+    {
+        WOLF_ERROR(server.getLog());
+        throw std::runtime_error("Solver could not be created! Missing type or plugin");
+    }
+
+    // Load plugin if factory not registered
+    auto solver_type = _param_node["type"].as<std::string>();
+    if (not FactorySolverNode::isCreatorRegistered(solver_type))
+    {
+        loadPlugin(_loader, _param_node["plugin"].as<std::string>());
+        if (not FactorySolverNode::isCreatorRegistered(solver_type))
+            throw std::runtime_error("Solver creator not registered after loading its plugin.");
+    }
+
+    // Create sensor
+    return FactorySolverNode::create(solver_type, _problem, _param_node, _schema_folders);
+}
+
 void SolverManager::update()
 {
     // lock mutex to prevent Problem::transform() during this update()
@@ -690,28 +743,29 @@ bool SolverManager::check(std::string prefix) const
 
 void SolverManager::printProfiling(std::ostream& _stream) const
 {
-    _stream << "\nSolverManager:"
-            << "\nTotal values:"
-            << "\n\tSolving state:          " << 1e-6 * acc_duration_total_.count() << " s - executions: " << n_solve_
-            << "\n\t\tUpdate problem:   " << 1e-6 * acc_duration_update_.count() << " s"
-            << " (" << 100.0 * acc_duration_update_.count() / acc_duration_total_.count() << " %)"
-            << "\n\t\tSolver:           " << 1e-6 * acc_duration_solver_.count() << " s"
-            << " (" << 100.0 * acc_duration_solver_.count() / acc_duration_total_.count() << " %)"
-            << "\n\t\tUpdate state:     " << 1e-6 * acc_duration_state_.count() << " s"
-            << " (" << 100.0 * acc_duration_state_.count() / acc_duration_total_.count() << " %)"
-            << "\n\tSolving covariance:     " << 1e-6 * acc_duration_cov_.count() << " s - executions: " << n_cov_
-            << "\nAverage:"
-            << "\n\tSolving state:          " << 1e-3 * acc_duration_total_.count() / n_solve_ << " ms"
-            << "\n\t\tUpdate problem:   " << 1e-3 * acc_duration_update_.count() / n_solve_ << " ms"
-            << "\n\t\tSolver:           " << 1e-3 * acc_duration_solver_.count() / n_solve_ << " ms"
-            << "\n\t\tUpdate state:     " << 1e-3 * acc_duration_state_.count() / n_solve_ << " ms"
-            << "\n\tSolving covariance:     " << 1e-3 * acc_duration_cov_.count() / n_cov_ << " ms"
-            << "\nMax values:"
-            << "\n\tSolving state:          " << 1e-3 * max_duration_total_.count() << " ms"
-            << "\n\t\tUpdate problem:   " << 1e-3 * max_duration_update_.count() << " ms"
-            << "\n\t\tSolver:           " << 1e-3 * max_duration_solver_.count() << " ms"
-            << "\n\t\tUpdate state:     " << 1e-3 * max_duration_state_.count() << " ms"
-            << "\n\tSolving covariance:     " << 1e-3 * max_duration_cov_.count() << " ms" << std::endl;
+    _stream << "\nSolverManager:"  //
+            << "\nTotal values:"   //
+            << "\n\tSolving state:          " << 1e-6 * acc_duration_total_.count()
+            << " s - executions: " << n_solve_                                                                      //
+            << "\n\t\tUpdate problem:   " << 1e-6 * acc_duration_update_.count() << " s"                            //
+            << " (" << 100.0 * acc_duration_update_.count() / acc_duration_total_.count() << " %)"                  //
+            << "\n\t\tSolver:           " << 1e-6 * acc_duration_solver_.count() << " s"                            //
+            << " (" << 100.0 * acc_duration_solver_.count() / acc_duration_total_.count() << " %)"                  //
+            << "\n\t\tUpdate state:     " << 1e-6 * acc_duration_state_.count() << " s"                             //
+            << " (" << 100.0 * acc_duration_state_.count() / acc_duration_total_.count() << " %)"                   //
+            << "\n\tSolving covariance:     " << 1e-6 * acc_duration_cov_.count() << " s - executions: " << n_cov_  //
+            << "\nAverage:"                                                                                         //
+            << "\n\tSolving state:          " << 1e-3 * acc_duration_total_.count() / n_solve_ << " ms"             //
+            << "\n\t\tUpdate problem:   " << 1e-3 * acc_duration_update_.count() / n_solve_ << " ms"                //
+            << "\n\t\tSolver:           " << 1e-3 * acc_duration_solver_.count() / n_solve_ << " ms"                //
+            << "\n\t\tUpdate state:     " << 1e-3 * acc_duration_state_.count() / n_solve_ << " ms"                 //
+            << "\n\tSolving covariance:     " << 1e-3 * acc_duration_cov_.count() / n_cov_ << " ms"                 //
+            << "\nMax values:"                                                                                      //
+            << "\n\tSolving state:          " << 1e-3 * max_duration_total_.count() << " ms"                        //
+            << "\n\t\tUpdate problem:   " << 1e-3 * max_duration_update_.count() << " ms"                           //
+            << "\n\t\tSolver:           " << 1e-3 * max_duration_solver_.count() << " ms"                           //
+            << "\n\t\tUpdate state:     " << 1e-3 * max_duration_state_.count() << " ms"                            //
+            << "\n\tSolving covariance:     " << 1e-3 * max_duration_cov_.count() << " ms" << std::endl;            //
 
     printProfilingDerived(_stream);
 }