diff --git a/core/base/inc/TBuffer.h b/core/base/inc/TBuffer.h
index e764da8d9ab645a5eaa7c57b50120e06e45a1df1..d7470de30987d8ee29cc1d502b30a34e80dcf4cc 100644
--- a/core/base/inc/TBuffer.h
+++ b/core/base/inc/TBuffer.h
@@ -22,12 +22,12 @@
 //////////////////////////////////////////////////////////////////////////
 
 #include "TObject.h"
+#include "TClass.h"
 
 #include <vector>
 
 class TVirtualStreamerInfo;
 class TStreamerElement;
-class TClass;
 class TString;
 class TProcessID;
 class TClonesArray;
@@ -386,14 +386,14 @@ template <class Tmpl> TBuffer &operator>>(TBuffer &buf, Tmpl *&obj)
    // would not be sufficient to pass the information 'which class do we want'
    // since the pointer could be zero (so typeid(*obj) is not usable).
 
-   TClass *cl = TBuffer::GetClass(typeid(Tmpl));
+   auto cl = TClass::GetClass<Tmpl>();
    obj = (Tmpl *) ( (void*) buf.ReadObjectAny(cl) );
    return buf;
 }
 
 template <class Tmpl> TBuffer &operator<<(TBuffer &buf, const Tmpl *obj)
 {
-   TClass *cl = (obj) ? TBuffer::GetClass(typeid(*obj)) : 0;
+   auto cl = (obj) ? TClass::GetClass<Tmpl>() : nullptr;
    buf.WriteObjectAny(obj, cl);
    return buf;
 }
@@ -402,16 +402,10 @@ template <class Tmpl> TBuffer &operator>>(TBuffer &buf, Tmpl *&obj);
 template <class Tmpl> TBuffer &operator<<(TBuffer &buf, Tmpl *&obj);
 #endif
 
-#if defined(R__TEMPLATE_OVERLOAD_BUG)
-template <>
-#endif
-inline TBuffer &operator<<(TBuffer &buf, const TObject *obj)
-   { buf.WriteObjectAny(obj, TObject::Class()); return buf; }
-
 template <class T>
 inline Int_t TBuffer::WriteObject(const T *objptr, Bool_t cacheReuse)
 {
-   TClass *cl = (objptr) ? TBuffer::GetClass(typeid(T)) : 0;
+   auto cl = (objptr) ? TClass::GetClass<T>() : nullptr;
    return WriteObjectAny(objptr, cl, cacheReuse);
 }
 
diff --git a/core/meta/inc/TClass.h b/core/meta/inc/TClass.h
index be1c4d88b480f59470f6c528838db17ec5cc3877..825f2fddccd71d045243bc3091aff851d6521523 100644
--- a/core/meta/inc/TClass.h
+++ b/core/meta/inc/TClass.h
@@ -539,6 +539,8 @@ public:
    static TClass        *GetClass(const char *name, Bool_t load = kTRUE, Bool_t silent = kFALSE);
    static TClass        *GetClass(const std::type_info &typeinfo, Bool_t load = kTRUE, Bool_t silent = kFALSE);
    static TClass        *GetClass(ClassInfo_t *info, Bool_t load = kTRUE, Bool_t silent = kFALSE);
+   template<typename T>
+   static TClass        *GetClass(Bool_t load = kTRUE, Bool_t silent = kFALSE);
    static Bool_t         GetClass(DeclId_t id, std::vector<TClass*> &classes);
    static DictFuncPtr_t  GetDict (const char *cname);
    static DictFuncPtr_t  GetDict (const std::type_info &info);
@@ -572,6 +574,30 @@ public:
    ClassDef(TClass,0)  //Dictionary containing class information
 };
 
+namespace ROOT {
+namespace Internal {
+template <typename T>
+TClass *GetClassHelper(Bool_t, Bool_t, std::true_type)
+{
+   return T::Class();
+}
+
+template <typename T>
+TClass *GetClassHelper(Bool_t load, Bool_t silent, std::false_type)
+{
+   return TClass::GetClass(typeid(T), load, silent);
+}
+
+} // namespace Internal
+} // namespace ROOT
+
+template <typename T>
+TClass *TClass::GetClass(Bool_t load, Bool_t silent)
+{
+   typename std::is_base_of<TObject, T>::type tag;
+   return ROOT::Internal::GetClassHelper<T>(load, silent, tag);
+}
+
 namespace ROOT {
 
 template <typename T> TClass *GetClass(T * /* dummy */)       { return TClass::GetClass(typeid(T)); }
diff --git a/io/io/inc/TDirectoryFile.h b/io/io/inc/TDirectoryFile.h
index 919a0dec6a0a350bb67928b164f5b16add613811..81e3b82f0e0deadff85848c687fc9592a55f5442 100644
--- a/io/io/inc/TDirectoryFile.h
+++ b/io/io/inc/TDirectoryFile.h
@@ -78,7 +78,7 @@ public:
    virtual TDirectory *GetDirectory(const char *apath, Bool_t printError = false, const char *funcname = "GetDirectory");
    template <class T> inline void GetObject(const char* namecycle, T*& ptr) // See TDirectory::Get for information
       {
-         ptr = (T*)GetObjectChecked(namecycle,TBuffer::GetClass(typeid(T)));
+         ptr = (T*)GetObjectChecked(namecycle,TClass::GetClass<T>());
       }
    virtual void       *GetObjectChecked(const char *namecycle, const char* classname);
    virtual void       *GetObjectChecked(const char *namecycle, const TClass* cl);