diff --git a/src/multibody/joint/joint-base.hpp b/src/multibody/joint/joint-base.hpp
index 203d7849ddb1048655c6e4c8abf1b66a440772cf..ec9f3a3b5366f83082e8aef10a6336d8b88004a4 100644
--- a/src/multibody/joint/joint-base.hpp
+++ b/src/multibody/joint/joint-base.hpp
@@ -386,7 +386,17 @@ namespace se3
     
     std::string shortname() const { return derived().shortname(); }
     static std::string classname() { return Derived::classname(); }
-
+    
+    template <class OtherDerived>
+    bool operator==(const JointModelBase<OtherDerived> & other) const { return derived().isEqual(other); }
+    
+    template <class OtherDerived>
+    bool isEqual(const JointModelBase<OtherDerived> &) const { return false; }
+    
+    bool isEqual(const JointModelBase<Derived> & other) const
+    {
+      return other.id() == id() && other.idx_q() == idx_q() && other.idx_v() == idx_v();
+    }
 
     /* Acces to dedicated segment in robot config space.  */
     // Const access
@@ -420,7 +430,6 @@ namespace se3
     typename SizeDepType<NV>::template SegmentReturn<D>::Type 
     jointVelocitySelector_impl( Eigen::MatrixBase<D>& a) const { return a.template segment<NV>(i_v); }
 
-
     template<typename D>
     typename SizeDepType<NV>::template ColsReturn<D>::ConstType 
     jointCols(const Eigen::MatrixBase<D>& A) const       { return derived().jointCols_impl(A); }
diff --git a/src/multibody/joint/joint-dense.hpp b/src/multibody/joint/joint-dense.hpp
index 58eeb95a02bcf6c7b3560a8769daa368653e1654..324ef6251a535670cf7a253c23dba2d3b9e661a7 100644
--- a/src/multibody/joint/joint-dense.hpp
+++ b/src/multibody/joint/joint-dense.hpp
@@ -241,19 +241,6 @@ namespace se3
     static std::string classname() { return std::string("JointModelDense"); }
     std::string shortname() const { return classname(); }
 
-    template <class D>
-    bool operator == (const JointModelBase<D> &) const
-    {
-      return false;
-    }
-    
-    bool operator == (const JointModelBase<JointModelDense> & jmodel) const
-    {
-      return jmodel.id() == id()
-              && jmodel.idx_q() == idx_q()
-              && jmodel.idx_v() == idx_v();
-    }
-
   }; // struct JointModelDense
 
   template<>
diff --git a/src/multibody/joint/joint-free-flyer.hpp b/src/multibody/joint/joint-free-flyer.hpp
index 5b4f02c2b275919e64d2aa4cca26218ea5bae087..9edc40e1b8f9ab551e7b1c8f699b3d898db22da4 100644
--- a/src/multibody/joint/joint-free-flyer.hpp
+++ b/src/multibody/joint/joint-free-flyer.hpp
@@ -390,18 +390,6 @@ namespace se3
     static std::string classname() { return std::string("JointModelFreeFlyer"); }
     std::string shortname() const { return classname(); }
 
-    template <class D>
-    bool operator == (const JointModelBase<D> &) const
-    {
-      return false;
-    }
-    
-    bool operator == (const JointModelBase<JointModelFreeFlyer> & jmodel) const
-    {
-      return jmodel.id() == id()
-              && jmodel.idx_q() == idx_q()
-              && jmodel.idx_v() == idx_v();
-    }
   }; // struct JointModelFreeFlyer
 
 } // namespace se3
diff --git a/src/multibody/joint/joint-planar.hpp b/src/multibody/joint/joint-planar.hpp
index 2fdda2483176f3a2d0a4332a0420a5fa45fc3d0d..0f601fa30263362faffe785554d73bcf16402fcc 100644
--- a/src/multibody/joint/joint-planar.hpp
+++ b/src/multibody/joint/joint-planar.hpp
@@ -443,18 +443,6 @@ namespace se3
     static std::string classname() { return std::string("JointModelPlanar");}
     std::string shortname() const { return classname(); }
 
-    template <class D>
-    bool operator == (const JointModelBase<D> &) const
-    {
-      return false;
-    }
-    
-    bool operator == (const JointModelBase<JointModelPlanar> & jmodel) const
-    {
-      return jmodel.id() == id()
-              && jmodel.idx_q() == idx_q()
-              && jmodel.idx_v() == idx_v();
-    }
   }; // struct JointModelPlanar
 
 } // namespace se3
diff --git a/src/multibody/joint/joint-prismatic-unaligned.hpp b/src/multibody/joint/joint-prismatic-unaligned.hpp
index d27975c4ba410dcc4f80d81fbcf893b90de4d69e..e5393a2a8817cf2c1d6be4d46b9266f2fd3d4242 100644
--- a/src/multibody/joint/joint-prismatic-unaligned.hpp
+++ b/src/multibody/joint/joint-prismatic-unaligned.hpp
@@ -449,20 +449,6 @@ namespace se3
     static std::string classname() { return std::string("JointModelPrismaticUnaligned"); }
     std::string shortname() const { return classname(); }
 
-    template <class D>
-    bool operator== (const JointModelBase<D> &) const
-    {
-      return false;
-    }
-    
-    bool operator== (const JointModelBase<JointModelPrismaticUnaligned> & jmodel) const
-    {
-      return jmodel.id() == id()
-              && jmodel.idx_q() == idx_q()
-              && jmodel.idx_v() == idx_v();
-    }
-    
-  public:
     Vector3 axis;
   }; // struct JointModelPrismaticUnaligned
 
diff --git a/src/multibody/joint/joint-prismatic.hpp b/src/multibody/joint/joint-prismatic.hpp
index c00b2d1470ef12ae9320978a045bbef8c8001f85..b278c1136a37d0a566aacbb68d979967db89c461 100644
--- a/src/multibody/joint/joint-prismatic.hpp
+++ b/src/multibody/joint/joint-prismatic.hpp
@@ -504,18 +504,6 @@ namespace se3
     static std::string classname();
     std::string shortname() const { return classname(); }
 
-    template <class D>
-    bool operator == (const JointModelBase<D> &) const
-    {
-      return false;
-    }
-    
-    bool operator == (const JointModelBase<JointModelPrismatic> & jmodel) const
-    {
-      return jmodel.id() == id()
-              && jmodel.idx_q() == idx_q()
-              && jmodel.idx_v() == idx_v();
-    }
   }; // struct JointModelPrismatic
 
   typedef JointPrismatic<0> JointPX;
diff --git a/src/multibody/joint/joint-revolute-unaligned.hpp b/src/multibody/joint/joint-revolute-unaligned.hpp
index de08f861befb8c2117c59285ec3406839a0cd971..690fb3bc5eec994ebeaca6a3bd68161e6711cf02 100644
--- a/src/multibody/joint/joint-revolute-unaligned.hpp
+++ b/src/multibody/joint/joint-revolute-unaligned.hpp
@@ -453,20 +453,6 @@ namespace se3
     static std::string classname() { return std::string("JointModelRevoluteUnaligned"); }
     std::string shortname() const { return classname(); }
 
-    template <class D>
-    bool operator == (const JointModelBase<D> &) const
-    {
-      return false;
-    }
-    
-    bool operator == (const JointModelBase<JointModelRevoluteUnaligned> & jmodel) const
-    {
-      return jmodel.id() == id()
-              && jmodel.idx_q() == idx_q()
-              && jmodel.idx_v() == idx_v();
-    }
-    
-  public:
     Motion::Vector3 axis;
   }; // struct JointModelRevoluteUnaligned
 
diff --git a/src/multibody/joint/joint-revolute-unbounded.hpp b/src/multibody/joint/joint-revolute-unbounded.hpp
index 01f8992e21ff6b44adcdfc2e1dfe559b3d1df79c..4e06b542a03926d236398c3f0465d854024ac11a 100644
--- a/src/multibody/joint/joint-revolute-unbounded.hpp
+++ b/src/multibody/joint/joint-revolute-unbounded.hpp
@@ -254,19 +254,6 @@ namespace se3
     static std::string classname();
     std::string shortname() const { return classname(); }
 
-    template <class D>
-    bool operator == (const JointModelBase<D> &) const
-    {
-      return false;
-    }
-    
-    bool operator == (const JointModelBase<JointModelRevoluteUnbounded <axis> > & jmodel) const
-    {
-      return jmodel.id() == id()
-              && jmodel.idx_q() == idx_q()
-              && jmodel.idx_v() == idx_v();
-    }
-
   }; // struct JointModelRevoluteUnbounded
 
   typedef JointRevoluteUnbounded<0> JointRUBX;
diff --git a/src/multibody/joint/joint-revolute.hpp b/src/multibody/joint/joint-revolute.hpp
index d85d2fb11ce7dd43a4b390099a4d12204d4b6a50..70877c02e203dad4c640398a374e320ec0f27f44 100644
--- a/src/multibody/joint/joint-revolute.hpp
+++ b/src/multibody/joint/joint-revolute.hpp
@@ -538,19 +538,6 @@ namespace se3
     static std::string classname();
     std::string shortname() const { return classname(); }
 
-    template <class D>
-    bool operator == (const JointModelBase<D> &) const
-    {
-      return false;
-    }
-    
-    bool operator == (const JointModelBase<JointModelRevolute <axis> > & jmodel) const
-    {
-      return jmodel.id() == id()
-              && jmodel.idx_q() == idx_q()
-              && jmodel.idx_v() == idx_v();
-    }
-
   }; // struct JointModelRevolute
 
   typedef JointRevolute<0> JointRX;
diff --git a/src/multibody/joint/joint-spherical-ZYX.hpp b/src/multibody/joint/joint-spherical-ZYX.hpp
index 22ba87fabc930e1a066dfd08680068bec3add4c0..5c58d9b572cd34f42071d2256bd9280109953e36 100644
--- a/src/multibody/joint/joint-spherical-ZYX.hpp
+++ b/src/multibody/joint/joint-spherical-ZYX.hpp
@@ -470,19 +470,6 @@ namespace se3
     static std::string classname() { return std::string("JointModelSphericalZYX"); }
     std::string shortname() const { return classname(); }
 
-    template <class D>
-    bool operator == (const JointModelBase<D> &) const
-    {
-      return false;
-    }
-    
-    bool operator == (const JointModelBase<JointModelSphericalZYX> & jmodel) const
-    {
-      return jmodel.id() == id()
-              && jmodel.idx_q() == idx_q()
-              && jmodel.idx_v() == idx_v();
-    }
-
   }; // struct JointModelSphericalZYX
 
 } // namespace se3
diff --git a/src/multibody/joint/joint-spherical.hpp b/src/multibody/joint/joint-spherical.hpp
index 6c30e0f4af0027570d1a27259628fd6176b10055..05b8563708943994b372f50221026419eea00c09 100644
--- a/src/multibody/joint/joint-spherical.hpp
+++ b/src/multibody/joint/joint-spherical.hpp
@@ -415,18 +415,6 @@ namespace se3
     static std::string classname() { return std::string("JointModelSpherical"); }
     std::string shortname() const { return classname(); }
 
-    template <class D>
-    bool operator == (const JointModelBase<D> &) const
-    {
-      return false;
-    }
-    
-    bool operator == (const JointModelBase<JointModelSpherical> & jmodel) const
-    {
-      return jmodel.id() == id()
-              && jmodel.idx_q() == idx_q()
-              && jmodel.idx_v() == idx_v();
-    }
   }; // struct JointModelSpherical
 
 } // namespace se3
diff --git a/src/multibody/joint/joint-translation.hpp b/src/multibody/joint/joint-translation.hpp
index 182688ae370bf4a9c5323a36b67adf8df7d392ab..c78e63b425d79eeb7936976e52072201193003f6 100644
--- a/src/multibody/joint/joint-translation.hpp
+++ b/src/multibody/joint/joint-translation.hpp
@@ -382,18 +382,6 @@ namespace se3
     static std::string classname() { return std::string("JointModelTranslation"); }
     std::string shortname() const { return classname(); }
 
-    template <class D>
-    bool operator == (const JointModelBase<D> &) const
-    {
-      return false;
-    }
-    
-    bool operator == (const JointModelBase<JointModelTranslation> & jmodel) const
-    {
-      return jmodel.id() == id()
-              && jmodel.idx_q() == idx_q()
-              && jmodel.idx_v() == idx_v();
-    }
   }; // struct JointModelTranslation
   
 } // namespace se3
diff --git a/src/multibody/joint/joint.hpp b/src/multibody/joint/joint.hpp
index a2e6fb4d0b94443d7d60cf709f83cd5b6736c053..6017881eb006d8779833ba3672927f2e6be6fe4a 100644
--- a/src/multibody/joint/joint.hpp
+++ b/src/multibody/joint/joint.hpp
@@ -90,8 +90,9 @@ namespace se3
     typedef Joint JointDerived;
     SE3_JOINT_TYPEDEF;
     SE3_JOINT_USE_INDEXES;
-    using JointModelBase<JointModel>::id;
-    using JointModelBase<JointModel>::setIndexes;
+    using Base::id;
+    using Base::setIndexes;
+    using Base::operator==;
 
     JointModelVariant& toVariant() { return *static_cast<JointModelVariant*>(this); }
     const JointModelVariant& toVariant() const { return *static_cast<const JointModelVariant*>(this); }
@@ -159,20 +160,6 @@ namespace se3
     std::string shortname() const { return ::se3::shortname(*this); }
     static std::string classname() { return "JointModel"; }
 
-    template <class D>
-    bool operator == (const JointModelBase<D> &) const
-    {
-      return false;
-    }
-    
-    bool operator == (const JointModelBase<JointModel> & jmodel) const
-    {
-      return jmodel.id() == id()
-          && jmodel.idx_q() == idx_q()
-          && jmodel.idx_v() == idx_v();
-    }
-
-
     int     nq_impl() const { return ::se3::nq(*this); }
     int     nv_impl() const { return ::se3::nv(*this); }