diff --git a/Plugin/CMakeLists.txt b/Plugin/CMakeLists.txt
index f53e987a..b2b1aabc 100644
--- a/Plugin/CMakeLists.txt
+++ b/Plugin/CMakeLists.txt
@@ -4,6 +4,7 @@ set(HEADER_FILES
     ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/config.h.in
     ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/initModule.h
     ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/PythonEnvironment.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/PyBindHelper.h
     ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/SceneLoaderPY3.h
     ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/SpellingSuggestionHelper.h
 
diff --git a/Plugin/src/SofaPython3/PyBindHelper.h b/Plugin/src/SofaPython3/PyBindHelper.h
new file mode 100644
index 00000000..e8a5787b
--- /dev/null
+++ b/Plugin/src/SofaPython3/PyBindHelper.h
@@ -0,0 +1,190 @@
+/******************************************************************************
+*                              SofaPython3 plugin                             *
+*                  (c) 2021 CNRS, University of Lille, INRIA                  *
+*                                                                             *
+* This program is free software; you can redistribute it and/or modify it     *
+* under the terms of the GNU Lesser General Public License as published by    *
+* the Free Software Foundation; either version 2.1 of the License, or (at     *
+* your option) any later version.                                             *
+*                                                                             *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details.                                                           *
+*                                                                             *
+* You should have received a copy of the GNU Lesser General Public License    *
+* along with this program. If not, see <http://www.gnu.org/licenses/>.        *
+*******************************************************************************
+* Contact information: contact@sofa-framework.org                             *
+******************************************************************************/
+#pragma once
+
+#include <SofaPython3/config.h>
+#include <sofa/helper/logging/Messaging.h>
+#include <string>
+#include <vector>
+#include <regex>
+#include <pybind11/pybind11.h>
+
+namespace sofapython3
+{
+
+class PythonMethodDescription
+{
+public:
+    void add_entry(const std::string& signature="")
+    {
+        signatures.push_back(signature);
+        docstrings.push_back("");
+    }
+
+    /// Parse the docstring generated by pybind11 to extract the different method signatures
+    /// and for each the associated docstring.
+    void parse_docstring(const std::string& name, std::string docstring)
+    {
+        std::smatch m;
+        std::string last;
+        std::regex e;
+
+        if(signatures.size()==0)
+            return;
+
+        // easy path. Take the signature, then consider the remaining as a docstring
+        if(signatures.size()==1)
+        {
+            e = std::regex("("+name+".*)");
+            if (std::regex_search (docstring, m,e))
+            {
+                for (auto x:m)
+                    last = x;
+                if(signatures[0].size()==0)
+                    signatures[0] = last;
+                docstrings[0] = m.suffix().str();
+            }
+            return;
+        }
+
+        int idx = 0;
+        e = std::regex("(1\\. )("+name+".*)");
+        while (std::regex_search (docstring, m,e))
+        {
+            for (auto x:m)
+                last = x;
+
+            if(signatures[idx].size()==0)
+                signatures[idx] = last;
+
+            if(idx>0)
+                docstrings[idx-1] = m.prefix().str();
+            idx++;
+            docstring = m.suffix().str();
+
+            auto pex = "("+std::to_string(idx+1)+"\\. )("+name+".*)";
+            e = std::regex(pex);
+        }
+        if(!docstring.empty())
+            docstrings[idx-1] = docstring;
+    }
+
+    /// Generates the docstring from the extracted ones from pybind11 and applying the
+    /// customs signatures, if any.
+    const std::string build_docstring(const std::string& name) const
+    {
+        std::stringstream tmp;
+        if(signatures.size() == 1)
+        {
+            tmp << signatures[0];
+            tmp << docstrings[0];
+            return tmp.str();
+        }
+        else
+        {
+            tmp << name <<"(*args, **kwargs)\n";
+            tmp << "Overloaded function.\n\n";
+        }
+        for(unsigned int i=0;i<docstrings.size();i++)
+        {
+            tmp << (i+1) << ". " << signatures[i] ;
+            tmp << docstrings[i] ;
+        }
+        return tmp.str();
+    }
+
+private:
+    std::vector<std::string> signatures; //< signatures for the method overrides
+    std::vector<std::string> docstrings; //< docstrings for the method overrides
+
+};
+
+template<typename Class>
+class def_method
+{
+public:
+    def_method(Class classI, const std::string& name_) :
+        classInstance(classI), name(name_)
+    {
+    }
+
+    virtual ~def_method()
+    {
+        description.parse_docstring(name, get_current_docstring());
+        set_docstring(description.build_docstring(name));
+    }
+
+    template<typename ... Args>
+    def_method& add_override(Args ... args)
+    {
+        classInstance.def(name.c_str(), args...);
+        description.add_entry();
+        return *this;
+    }
+
+    template<typename ... Args>
+    def_method& add_override(const char* signature, Args ... args)
+    {
+        classInstance.def(name.c_str(), args...);
+        description.add_entry(signature);
+        return *this;
+    }
+
+    std::string get_current_docstring() const {
+        std::string tmp;
+        // get the raw python object out of the classInstance
+        auto method = classInstance.attr(name.c_str()).ptr();
+        // if it is an instance method get the raw CFunction
+        if(Py_TYPE(method) == &PyInstanceMethod_Type){
+            method = ((PyInstanceMethodObject*)(method))->func;
+        }
+        // if it is a CFunction, get its docstring
+        if(Py_TYPE(method) == &PyCFunction_Type){
+            auto cmethod = (PyCFunctionObject*)method;
+            tmp = std::string(cmethod->m_ml->ml_doc);
+        }
+        return tmp;
+    }
+
+    void set_docstring(const std::string& docstring) const
+    {
+        // get the raw python object out of the classInstance
+        auto method = classInstance.attr(name.c_str()).ptr();
+        // if it is an instance method get the raw CFunction
+        if(Py_TYPE(method) == &PyInstanceMethod_Type){
+            method = ((PyInstanceMethodObject*)(method))->func;
+        }
+        // if it is a CFunction, get its docstring
+        if(Py_TYPE(method) == &PyCFunction_Type){
+            auto cmethod = (PyCFunctionObject*)method;
+            cmethod->m_ml->ml_doc = strdup(docstring.c_str());
+        }else
+        {
+            msg_error("SofaPython3") << "Unable to build docstring for method " << name;
+        }
+    }
+
+private:
+    Class classInstance; //< stores the pybind::class_<XXX, >
+    std::string name;    //< stores the name of the method we declares
+    PythonMethodDescription description;
+};
+
+}
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp
index 6aa8d763..81365ecf 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp
@@ -449,12 +449,21 @@ py::object BindingBase::setDataValues(Base& self, py::kwargs kwargs)
     return py::none();
 }
 
+auto getBaseBinding(py::module& m)
+{
+    static py::class_<Base, py_shared_ptr<Base>> base(m, "Base", py::dynamic_attr(), doc::base::BaseClass);
+    return base;
+}
+
+void moduleForwardAddBase(py::module& m)
+{
+    getBaseBinding(m);
+}
+
 void moduleAddBase(py::module &m)
 {
-    moduleForwardAddBaseData(m);
-    moduleForwardAddBaseLink(m);
+    auto base = getBaseBinding(m);
 
-    py::class_<Base, py_shared_ptr<Base>> base(m, "Base", py::dynamic_attr(), doc::base::BaseClass);
     /// set & get the name as string. The alternative is to access the data field using
     /// obj.name.value = "aName"
     base.def("getName", [](Base& b){ return b.getName(); }, sofapython3::doc::base::getName);
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h
index 670ce54b..06a98e59 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h
@@ -68,7 +68,9 @@ class BindingBase
     static std::string getLinkPath(sofa::core::objectmodel::Base& self);
 };
 
-
+/// Forward declaration in pybind11.
+/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457
+void moduleForwardAddBase(pybind11::module& m);
 void moduleAddBase(pybind11::module& m);
 
 } /// namespace sofapython3
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.cpp
new file mode 100644
index 00000000..7fbbc0dd
--- /dev/null
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.cpp
@@ -0,0 +1,48 @@
+/******************************************************************************
+*                 SOFA, Simulation Open-Framework Architecture                *
+*                    (c) 2021 INRIA, USTL, UJF, CNRS, MGH                     *
+*                                                                             *
+* This program is free software; you can redistribute it and/or modify it     *
+* under the terms of the GNU Lesser General Public License as published by    *
+* the Free Software Foundation; either version 2.1 of the License, or (at     *
+* your option) any later version.                                             *
+*                                                                             *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details.                                                           *
+*                                                                             *
+* You should have received a copy of the GNU Lesser General Public License    *
+* along with this program. If not, see <http://www.gnu.org/licenses/>.        *
+*******************************************************************************
+* Contact information: contact@sofa-framework.org                             *
+******************************************************************************/
+
+#include <SofaPython3/Sofa/Core/Binding_BaseClass.h>
+#include <SofaPython3/Sofa/Core/Binding_BaseClass_doc.h>
+#include <sofa/core/objectmodel/BaseClass.h>
+
+namespace sofapython3
+{
+using namespace sofa::core::objectmodel;
+
+/// Makes an alias for the pybind11 namespace to increase readability.
+namespace py { using namespace pybind11; }
+
+auto getBaseClassBinding(py::module& m)
+{
+    static py::class_<BaseClass, std::unique_ptr<BaseClass, py::nodelete>> base(m, "BaseClass", doc::baseclass::classdocstring);
+    return base;
+}
+
+void moduleForwardAddBaseClass(py::module& m)
+{
+    getBaseClassBinding(m);
+}
+
+void moduleAddBaseClass(py::module &m)
+{
+    // adds here the BaseClass's binded function (if any).
+}
+
+} /// namespace sofapython3
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.h
new file mode 100644
index 00000000..6ae2c6b7
--- /dev/null
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+*                 SOFA, Simulation Open-Framework Architecture                *
+*                    (c) 2021 INRIA, USTL, UJF, CNRS, MGH                     *
+*                                                                             *
+* This program is free software; you can redistribute it and/or modify it     *
+* under the terms of the GNU Lesser General Public License as published by    *
+* the Free Software Foundation; either version 2.1 of the License, or (at     *
+* your option) any later version.                                             *
+*                                                                             *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details.                                                           *
+*                                                                             *
+* You should have received a copy of the GNU Lesser General Public License    *
+* along with this program. If not, see <http://www.gnu.org/licenses/>.        *
+*******************************************************************************
+* Contact information: contact@sofa-framework.org                             *
+******************************************************************************/
+
+#pragma once
+
+#include <pybind11/pybind11.h>
+
+namespace sofapython3 {
+
+/// Forward declaration in pybind11.
+/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457
+void moduleForwardAddBaseClass(pybind11::module& m);
+void moduleAddBaseClass(pybind11::module& m);
+
+} /// namespace sofapython3
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass_doc.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass_doc.h
new file mode 100644
index 00000000..2ed3d7d3
--- /dev/null
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass_doc.h
@@ -0,0 +1,31 @@
+/******************************************************************************
+*                 SOFA, Simulation Open-Framework Architecture                *
+*                    (c) 2021 INRIA, USTL, UJF, CNRS, MGH                     *
+*                                                                             *
+* This program is free software; you can redistribute it and/or modify it     *
+* under the terms of the GNU Lesser General Public License as published by    *
+* the Free Software Foundation; either version 2.1 of the License, or (at     *
+* your option) any later version.                                             *
+*                                                                             *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details.                                                           *
+*                                                                             *
+* You should have received a copy of the GNU Lesser General Public License    *
+* along with this program. If not, see <http://www.gnu.org/licenses/>.        *
+*******************************************************************************
+* Contact information: contact@sofa-framework.org                             *
+******************************************************************************/
+
+#pragma once
+
+namespace sofapython3::doc::baseclass {
+
+static auto classdocstring =
+        R"(Class hierarchy reflection base class
+This class provides information on the class and parent classes of components.
+It is created by using the SOFA_CLASS macro on each new class declaration.
+All classes deriving from Base should use the SOFA_CLASS macro within their declaration.)";
+
+}
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp
index ecc83750..d00341e6 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp
@@ -207,8 +207,6 @@ void moduleForwardAddBaseData(py::module& m)
 void moduleAddBaseData(py::module& m)
 {
     /// Register the BaseData binding into the pybind11 system.
-    //py::class_<BaseData, std::unique_ptr<sofa::core::objectmodel::BaseData, pybind11::nodelete>> data(m, "Data", sofapython3::doc::baseData::BaseDataClass);
-
     auto data =getPythonClassForBaseData(m);
     data.def("getName", [](BaseData& b){ return b.getName(); }, sofapython3::doc::baseData::getName);
     data.def("setName", [](BaseData& b, const std::string& s){ b.setName(s); }, sofapython3::doc::baseData::setName);
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h
index badd6522..54be7010 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h
@@ -24,6 +24,8 @@
 
 namespace sofapython3 {
 
+    /// Forward declaration in pybind11.
+    /// more details in: https://github.com/sofa-framework/SofaPython3/pull/457
     void moduleForwardAddBaseData(pybind11::module& m);
     void moduleAddBaseData(pybind11::module& m);
 
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h
index 1cf5df4a..7beca2fa 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h
@@ -24,6 +24,8 @@
 
 namespace sofapython3 {
 
+    /// Forward declaration in pybind11.
+    /// more details in: https://github.com/sofa-framework/SofaPython3/pull/457
     void moduleForwardAddBaseLink(pybind11::module& m);
     void moduleAddBaseLink(pybind11::module& m);
 
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.cpp
index 2759c530..886179b0 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.cpp
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.cpp
@@ -21,6 +21,7 @@
 
 #include <SofaPython3/Sofa/Core/Binding_Base.h>
 #include <SofaPython3/Sofa/Core/Binding_BaseContext.h>
+#include <SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h>
 #include <SofaPython3/PythonFactory.h>
 #include <sofa/core/BaseState.h>
 #include <sofa/core/objectmodel/BaseObject.h>
@@ -36,8 +37,21 @@ using namespace sofa::core::topology;
 
 namespace sofapython3 {
 
+
+auto getPythonClassForBaseMeshTopology(py::module& m)
+{
+    /// Register the BaseData binding into the pybind11 system.
+   static py::class_<BaseMeshTopology, Topology, py_shared_ptr<BaseMeshTopology>> basemesh(m, "BaseMeshTopology");
+   return basemesh;
+}
+
+void moduleForwardAddBaseMeshTopology(py::module& m)
+{
+    getPythonClassForBaseMeshTopology(m);
+}
+
 void moduleAddBaseMeshTopology(py::module& m) {
-    py::class_<BaseMeshTopology, Topology, py_shared_ptr<BaseMeshTopology>> c (m, "BaseMeshTopology");
+    auto c = getPythonClassForBaseMeshTopology(m);
 
     /// register the BaseMeshTopology binding in the downcasting subsystem
     PythonFactory::registerType<BaseMeshTopology>([](sofa::core::objectmodel::Base* object)
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h
index db28451e..7f8dd115 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h
@@ -24,6 +24,9 @@
 
 namespace sofapython3 {
 
+/// Forward declaration in pybind11.
+/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457
+void moduleForwardAddBaseMeshTopology(pybind11::module &m);
 void moduleAddBaseMeshTopology(pybind11::module &m);
 
 } // namespace sofapython3
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp
index 7f9a476c..06fe77b6 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp
@@ -188,10 +188,21 @@ py::object __getitem__(BaseObject &self, std::string s)
     return getItem(self, s);
 }
 
-void moduleAddBaseObject(py::module& m)
+auto getBaseObjectBinding(py::module& m)
 {
     /// Register the BaseObject binding into the pybind11 typing system
-    py::class_<BaseObject, Base, py_shared_ptr<BaseObject>>p(m, "Object", sofapython3::doc::baseObject::Class);
+    static py::class_<BaseObject, Base, py_shared_ptr<BaseObject>>p(m, "Object", sofapython3::doc::baseObject::Class);
+    return p;
+}
+
+void moduleForwardAddBaseObject(py::module& m)
+{
+    getBaseObjectBinding(m);
+}
+
+void moduleAddBaseObject(py::module& m)
+{
+    auto p = getBaseObjectBinding(m);
 
     /// Register the BaseObject binding into the downcasting subsystem
     PythonFactory::registerType<sofa::core::objectmodel::BaseObject>(
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.h
index 3e40176d..b85eed1f 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.h
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.h
@@ -29,6 +29,8 @@ class BaseObject;
 namespace sofapython3 {
 
 pybind11::object getItem(const sofa::core::objectmodel::BaseObject & self, const std::string& path);
+
+void moduleForwardAddBaseObject(pybind11::module &m);
 void moduleAddBaseObject(pybind11::module &m);
 
 } /// namespace sofapython
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp
index 75af4211..268b7a0d 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp
@@ -94,4 +94,10 @@ void moduleAddMass(py::module &m) {
     declare_mass<sofa::defaulttype::Rigid2dTypes>(m);
 }
 
+void moduleForwardAddBaseMass(py::module& m)
+{
+    static py::class_<sofa::core::behavior::BaseMass,
+            sofa::core::Base, py_shared_ptr<sofa::core::behavior::BaseMass>> basemass(m, "BaseMass");
+}
+
 }  // namespace sofapython3
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h
index 826b78da..7316b6ab 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h
@@ -24,6 +24,9 @@
 
 namespace sofapython3 {
 
+/// Forward declaration in pybind11.
+/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457
+void moduleForwardAddBaseMass(pybind11::module &m);
 void moduleAddMass(pybind11::module &m);
 
 } /// namespace sofapython3
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp
index dda992d1..f20275db 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp
@@ -61,6 +61,7 @@ using sofapython3::PythonEnvironment;
 #include <SofaPython3/Sofa/Core/Binding_PythonScriptEvent.h>
 
 #include <SofaPython3/SpellingSuggestionHelper.h>
+#include <SofaPython3/PyBindHelper.h>
 
 using sofa::core::objectmodel::BaseObjectDescription;
 
@@ -294,6 +295,12 @@ py::object addObjectKwargs(Node* self, const std::string& type, const py::kwargs
     return PythonFactory::toPython(object.get());
 }
 
+py::object addObjectGenericType(Node* self, const py::type type, const py::kwargs& kwargs)
+{
+    auto name = py::cast<std::string>(type.attr("__name__"));
+    return addObjectKwargs(self, name, kwargs);
+}
+
 /// Implement the addObject function.
 py::object addKwargs(Node* self, const py::object& callable, const py::kwargs& kwargs)
 {
@@ -605,61 +612,69 @@ void sendEvent(Node* self, py::object pyUserData, char* eventName)
     sofapython3::PythonScriptEvent event(self, eventName, pyUserData);
     self->propagateEvent(sofa::core::execparams::defaultInstance(), &event);
 }
-
 }
 
 void moduleAddNode(py::module &m) {
-    /// Register the complete parent-child relationship between Base and Node to the pybind11
-    /// typing system.
-    py::class_<sofa::core::objectmodel::BaseNode,
-            sofa::core::objectmodel::Base,
-            py_shared_ptr<sofa::core::objectmodel::BaseNode>>(m, "BaseNode");
-
-    py::class_<Node, sofa::core::objectmodel::BaseNode,
-            sofa::core::objectmodel::Context, py_shared_ptr<Node>>
-            p(m, "Node", sofapython3::doc::sofa::core::Node::Class);
-
-    PythonFactory::registerType<sofa::simulation::graph::DAGNode>(
-                [](sofa::core::objectmodel::Base* object)
     {
-        return py::cast(dynamic_cast<Node*>(object->toBaseNode()));
-    });
-
-    p.def(py::init(&__init__noname), sofapython3::doc::sofa::core::Node::init);
-    p.def(py::init(&__init__), sofapython3::doc::sofa::core::Node::init1Arg, py::arg("name"));
-    p.def("init", &init, sofapython3::doc::sofa::core::Node::initSofa );
-    p.def("add", &addKwargs, sofapython3::doc::sofa::core::Node::addKwargs);
-    p.def("addObject", &addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs);
-    p.def("addObject", &addObject, sofapython3::doc::sofa::core::Node::addObject, py::keep_alive<0, 2>());
-    p.def("createObject", &createObject, sofapython3::doc::sofa::core::Node::createObject, py::keep_alive<0, 2>());
-    p.def("hasObject", &hasObject, sofapython3::doc::sofa::core::Node::hasObject);
-    p.def("getObject", &getObject, sofapython3::doc::sofa::core::Node::getObject);
-    p.def("addChild", &addChildKwargs, sofapython3::doc::sofa::core::Node::addChildKwargs);
-    p.def("addChild", &addChild, sofapython3::doc::sofa::core::Node::addChild, py::keep_alive<0, 2>());
-    p.def("createChild", &createChild, sofapython3::doc::sofa::core::Node::createChild, py::keep_alive<0, 2>());
-    p.def("getChild", &getChild, sofapython3::doc::sofa::core::Node::getChild);
-    p.def("removeChild", &removeChild, sofapython3::doc::sofa::core::Node::removeChild);
-    p.def("removeChild", &removeChildByName, sofapython3::doc::sofa::core::Node::removeChildWithName);
-    p.def("getRoot", &getRoot, sofapython3::doc::sofa::core::Node::getRoot);
-    p.def("getPathName", &Node::getPathName, sofapython3::doc::sofa::core::Node::getPathName);
-    p.def("getLinkPath", &getLinkPath, sofapython3::doc::sofa::core::Node::getLinkPath);
-    p.def_property_readonly("children", &property_children, sofapython3::doc::sofa::core::Node::children);
-    p.def_property_readonly("parents", &property_parents, sofapython3::doc::sofa::core::Node::parents);
-    p.def_property_readonly("objects", &property_objects, sofapython3::doc::sofa::core::Node::objects);
-    p.def("__getattr__", &__getattr__);
-    p.def("__getitem__", &__getitem__);
-    p.def("removeObject", &removeObject, sofapython3::doc::sofa::core::Node::removeObject);
-    p.def("getRootPath", &Node::getRootPath, sofapython3::doc::sofa::core::Node::getRootPath);
-    p.def("moveChild", &moveChild, sofapython3::doc::sofa::core::Node::moveChild);
-    p.def("isInitialized", &Node::isInitialized, sofapython3::doc::sofa::core::Node::isInitialized);
-    p.def("getAsACreateObjectParameter", &getLinkPath, sofapython3::doc::sofa::core::Node::getAsACreateObjectParameter);
-    p.def("detachFromGraph", &Node::detachFromGraph, sofapython3::doc::sofa::core::Node::detachFromGraph);
-    p.def("getMass", &getMass, sofapython3::doc::sofa::core::Node::getMass);
-    p.def("hasODESolver", &hasODESolver, sofapython3::doc::sofa::core::Node::hasODESolver);
-    p.def("getForceField", &getForceField, sofapython3::doc::sofa::core::Node::getForceField);
-    p.def("getMechanicalState", &getMechanicalState, sofapython3::doc::sofa::core::Node::getMechanicalState);
-    p.def("getMechanicalMapping", &getMechanicalMapping, sofapython3::doc::sofa::core::Node::getMechanicalMapping);
-    p.def("sendEvent", &sendEvent, sofapython3::doc::sofa::core::Node::sendEvent);
+        /// Register the complete parent-child relationship between Base and Node to the pybind11
+        /// typing system.
+        py::class_<sofa::core::objectmodel::BaseNode,
+                sofa::core::objectmodel::Base,
+                py_shared_ptr<sofa::core::objectmodel::BaseNode>>(m, "BaseNode");
+
+        py::class_<Node, sofa::core::objectmodel::BaseNode,
+                sofa::core::objectmodel::Context, py_shared_ptr<Node>>
+                p(m, "Node", sofapython3::doc::sofa::core::Node::Class);
+
+        PythonFactory::registerType<sofa::simulation::graph::DAGNode>(
+                    [](sofa::core::objectmodel::Base* object)
+        {
+            return py::cast(dynamic_cast<Node*>(object->toBaseNode()));
+        });
+
+        p.def(py::init(&__init__noname), sofapython3::doc::sofa::core::Node::init);
+        p.def(py::init(&__init__), sofapython3::doc::sofa::core::Node::init1Arg, py::arg("name"));
+        p.def("init", &init, sofapython3::doc::sofa::core::Node::initSofa );
+        p.def("add", &addKwargs, sofapython3::doc::sofa::core::Node::addKwargs);
+
+        def_method(p, "addObject")
+                .add_override("addObject(self, typename: str, **kwargs) -> Sofa.Core.Object",
+                              addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs)
+                .add_override(addObject,
+                              sofapython3::doc::sofa::core::Node::addObject, py::keep_alive<0, 2>())
+                .add_override("addObject[T](self, python_type: type, **kwargs) -> T",
+                              addObjectGenericType, sofapython3::doc::sofa::core::Node::addObjectGenerictype);
+
+        p.def("createObject", &createObject, sofapython3::doc::sofa::core::Node::createObject, py::keep_alive<0, 2>());
+        p.def("hasObject", &hasObject, sofapython3::doc::sofa::core::Node::hasObject);
+        p.def("getObject", &getObject, sofapython3::doc::sofa::core::Node::getObject);
+        p.def("addChild", &addChildKwargs, sofapython3::doc::sofa::core::Node::addChildKwargs);
+        p.def("addChild", &addChild, sofapython3::doc::sofa::core::Node::addChild, py::keep_alive<0, 2>());
+        p.def("createChild", &createChild, sofapython3::doc::sofa::core::Node::createChild, py::keep_alive<0, 2>());
+        p.def("getChild", &getChild, sofapython3::doc::sofa::core::Node::getChild);
+        p.def("removeChild", &removeChild, sofapython3::doc::sofa::core::Node::removeChild);
+        p.def("removeChild", &removeChildByName, sofapython3::doc::sofa::core::Node::removeChildWithName);
+        p.def("getRoot", &getRoot, sofapython3::doc::sofa::core::Node::getRoot);
+        p.def("getPathName", &Node::getPathName, sofapython3::doc::sofa::core::Node::getPathName);
+        p.def("getLinkPath", &getLinkPath, sofapython3::doc::sofa::core::Node::getLinkPath);
+        p.def_property_readonly("children", &property_children, sofapython3::doc::sofa::core::Node::children);
+        p.def_property_readonly("parents", &property_parents, sofapython3::doc::sofa::core::Node::parents);
+        p.def_property_readonly("objects", &property_objects, sofapython3::doc::sofa::core::Node::objects);
+        p.def("__getattr__", &__getattr__);
+        p.def("__getitem__", &__getitem__);
+        p.def("removeObject", &removeObject, sofapython3::doc::sofa::core::Node::removeObject);
+        p.def("getRootPath", &Node::getRootPath, sofapython3::doc::sofa::core::Node::getRootPath);
+        p.def("moveChild", &moveChild, sofapython3::doc::sofa::core::Node::moveChild);
+        p.def("isInitialized", &Node::isInitialized, sofapython3::doc::sofa::core::Node::isInitialized);
+        p.def("getAsACreateObjectParameter", &getLinkPath, sofapython3::doc::sofa::core::Node::getAsACreateObjectParameter);
+        p.def("detachFromGraph", &Node::detachFromGraph, sofapython3::doc::sofa::core::Node::detachFromGraph);
+        p.def("getMass", &getMass, sofapython3::doc::sofa::core::Node::getMass);
+        p.def("hasODESolver", &hasODESolver, sofapython3::doc::sofa::core::Node::hasODESolver);
+        p.def("getForceField", &getForceField, sofapython3::doc::sofa::core::Node::getForceField);
+        p.def("getMechanicalState", &getMechanicalState, sofapython3::doc::sofa::core::Node::getMechanicalState);
+        p.def("getMechanicalMapping", &getMechanicalMapping, sofapython3::doc::sofa::core::Node::getMechanicalMapping);
+        p.def("sendEvent", &sendEvent, sofapython3::doc::sofa::core::Node::sendEvent);
+    }
 
 }
 } /// namespace sofapython3
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.h
index 9224ab1d..608eadbe 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.h
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.h
@@ -23,6 +23,7 @@
 
 namespace sofapython3 {
 
+void moduleForwardAddNode(pybind11::module& m);
 void moduleAddNode(pybind11::module &m);
 
 } /// namespace sofapython3
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h
index 3f971926..1aa62f97 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h
@@ -84,8 +84,8 @@ static auto Class =
 
              # fast access.
              n["child1.child2.dofs.position"]
-
         )";
+
 static auto init =
         R"(
         Initialize the components of this node and all the nodes which depend on it.
@@ -123,27 +123,30 @@ static auto addKwargs =
             node.add(Cube, name="MyCube"")
         )";
 
-
 static auto addObjectKwargs =
         R"(
-        Add an object.
+        Creates and add a new sofa object to the node.
         Detect the implemented interfaces and add the object to the corresponding lists.
         :param self: the node itself
-        :param type: type of the object
-        :param kwargs
-        :type self: Sofa.Simulation.Node*
-        :type type: string&
-        :type kwargs: kwargs&
+        :param typename: name of the type of the object to create
+        :param kwargs: extra parameteres to initialize the created object.
+        )";
+
+static auto addObjectGenerictype =
+        R"(
+        Creates and add a new sofa object to the node.
+        :param self: the node itself
+        :param type: the component's type to add, type's name is used as sofa factory's type name
+        :return: the created component
         )";
 
 static auto addObject =
         R"(
-        Add an object.
+        Adds an existing object to the node.
         Detect the implemented interfaces and add the object to the corresponding lists.
         :param self: the node itself
-        :param object: the object to be added
-        :type self: Sofa.Simulation.Node&
-        :type object: Sofa.Simulation.BaseObject*
+        :param object: the component to add
+        :return: the added component
         )";
 
 static auto createObject =
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.cpp
index ed57ba11..63c182c5 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.cpp
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.cpp
@@ -35,8 +35,17 @@ using namespace sofa::core::topology;
 
 namespace sofapython3 {
 
+auto getTopologyClass(py::module& m){
+    static py::class_<Topology, BaseObject, py_shared_ptr<Topology>> c (m, "Topology");
+    return c;
+}
+
+void moduleForwardAddTopology(py::module& m) {
+    getTopologyClass(m);
+}
+
 void moduleAddTopology(py::module& m) {
-    py::class_<Topology, BaseObject, py_shared_ptr<Topology>> c (m, "Topology");
+    getTopologyClass(m);
 }
 
 } // namespace sofapython3
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.h
index 5f89f0e1..4bd7d4d1 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.h
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.h
@@ -24,6 +24,9 @@
 
 namespace sofapython3 {
 
+/// Forward declaration in pybind11.
+/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457
+void moduleForwardAddTopology(pybind11::module &m);
 void moduleAddTopology(pybind11::module &m);
 
 } // namespace sofapython3
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt
index 6dad5fea..d7ff4fd7 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt
@@ -3,6 +3,8 @@ project(Bindings.Sofa.Core)
 set(HEADER_FILES
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Base.h
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Base_doc.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseClass.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseClass_doc.h
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_DataDict.h
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_DataDict_doc.h
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseData.h
@@ -51,6 +53,7 @@ set(HEADER_FILES
 
 set(SOURCE_FILES
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Base.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseClass.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseData.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_DataDict.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseObject.cpp
@@ -72,12 +75,12 @@ set(SOURCE_FILES
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_NodeIterator.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_PointSetTopologyModifier.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Prefab.cpp
-    ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Core.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_PythonScriptEvent.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseLink.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Topology.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseMeshTopology.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Binding_TaskScheduler.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Core.cpp
 )
 
 if (NOT TARGET SofaPython3::Plugin)
diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp
index 546bb435..462d220c 100644
--- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp
+++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp
@@ -23,6 +23,7 @@
 using sofa::helper::logging::Message;
 
 #include <SofaPython3/Sofa/Core/Binding_Base.h>
+#include <SofaPython3/Sofa/Core/Binding_BaseClass.h>
 #include <SofaPython3/Sofa/Core/Binding_BaseContext.h>
 #include <SofaPython3/Sofa/Core/Binding_BaseObject.h>
 #include <SofaPython3/Sofa/Core/Binding_DataDict.h>
@@ -44,6 +45,7 @@ using sofa::helper::logging::Message;
 #include <SofaPython3/Sofa/Core/Binding_PythonScriptEvent.h>
 #include <SofaPython3/Sofa/Core/Binding_Topology.h>
 #include <SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h>
+#include <SofaPython3/Sofa/Core/Binding_Topology.h>
 #include <SofaPython3/Sofa/Core/Binding_TaskScheduler.h>
 
 #include <SofaPython3/Sofa/Core/Data/Binding_DataString.h>
@@ -103,6 +105,27 @@ PYBIND11_MODULE(Core, core)
                #Sofa.Core.WriteAccessor
        )doc";
 
+
+
+    /// Forward declaration of a class in pybind11.
+    /// The general idea is that to avoid typeing errors in pybind11 because of -yet- to
+    /// define classes it is needed to register binded class before any use (including use
+    /// in function signature inferance)
+    /// more details in: https://github.com/sofa-framework/SofaPython3/pull/457
+    moduleForwardAddBaseClass(core);
+    moduleForwardAddBase(core);
+    moduleForwardAddBaseObject(core);
+    moduleForwardAddBaseData(core);
+    moduleForwardAddBaseLink(core);
+    moduleForwardAddTopology(core);
+    moduleForwardAddBaseMeshTopology(core);
+    moduleForwardAddBaseMass(core);
+
+    py::class_<sofa::core::behavior::BaseMechanicalState,
+            Base, py_shared_ptr<sofa::core::behavior::BaseMechanicalState>> basems(core, "BaseMechanicalState");
+
+    /// When all forward declarations in pybind11 are done we can actually fully
+    /// define the full binding.
     moduleAddPythonScriptEvent();
     moduleAddDataDict(core);
     moduleAddDataDictIterator(core);
@@ -143,7 +166,6 @@ PYBIND11_MODULE(Core, core)
 
         msg_info("SofaPython3.Core") << "Sofa.Core unload()";
     }));
-
 }
 
 } ///namespace sofapython3