diff --git a/bindings/pyroot/src/Cppyy.cxx b/bindings/pyroot/src/Cppyy.cxx
index 87c18b3a64eb703d28bfc8bd1e790b3bb322be99..37286b1afe9bae9c06b5e639da7fb7e8a1ef02e8 100644
--- a/bindings/pyroot/src/Cppyy.cxx
+++ b/bindings/pyroot/src/Cppyy.cxx
@@ -538,6 +538,9 @@ size_t Cppyy::GetFunctionArgTypeoffset()\
 // scope reflection information ----------------------------------------------
 Bool_t Cppyy::IsNamespace( TCppScope_t scope ) {
 // Test if this scope represents a namespace.
+   if (scope == GLOBAL_HANDLE)
+      return kTRUE;
+
    TClassRef& cr = type_from_handle( scope );
    if ( cr.GetClass() )
       return cr->Property() & kIsNamespace;
@@ -816,6 +819,33 @@ Bool_t Cppyy::IsConstMethod( TCppMethod_t method )
 }
 
 
+bool Cppyy::ExistsMethodTemplate(TCppScope_t scope, const std::string& name)
+{
+   if (scope == (TCppScope_t)GLOBAL_HANDLE) {
+      return (bool)gROOT->GetFunctionTemplate(name.c_str());
+   } else {
+      TClassRef& cr = type_from_handle(scope);
+      if (cr.GetClass())
+         return (bool)cr->GetFunctionTemplate(name.c_str());
+   }
+
+   return false;
+}
+
+Cppyy::TCppMethod_t Cppyy::GetMethodTemplate(
+   TCppScope_t scope, const std::string& name, const std::string& proto)
+{
+   if (scope == (TCppScope_t)GLOBAL_HANDLE) {
+      return (TCppMethod_t)gROOT->GetGlobalFunctionWithPrototype(name.c_str(), proto.c_str());
+   } else {
+      TClassRef& cr = type_from_handle(scope);
+      if (cr.GetClass())
+         return (TCppMethod_t)cr->GetMethodWithPrototype(name.c_str(), proto.c_str());
+   }
+
+   return (TCppMethod_t)nullptr;
+}
+
 Bool_t Cppyy::IsMethodTemplate( TCppMethod_t method )
 {
    if ( method ) {
diff --git a/bindings/pyroot/src/Cppyy.h b/bindings/pyroot/src/Cppyy.h
index e3b331a415c4c4c11a9cbda42bbdba7fbf29d130..67cf01523839fe8b2f136a9ac0f34a5e43d47d86 100644
--- a/bindings/pyroot/src/Cppyy.h
+++ b/bindings/pyroot/src/Cppyy.h
@@ -99,6 +99,8 @@ namespace Cppyy {
    std::string GetMethodSignature( TCppScope_t scope, TCppIndex_t imeth );
    Bool_t      IsConstMethod( TCppMethod_t );
 
+   bool        ExistsMethodTemplate(TCppScope_t scope, const std::string& name);
+   TCppMethod_t GetMethodTemplate(TCppScope_t scope, const std::string& name, const std::string& proto);
    Bool_t      IsMethodTemplate( TCppMethod_t );
    TCppIndex_t GetMethodNumTemplateArgs( TCppScope_t scope, TCppIndex_t imeth );
    std::string GetMethodTemplateArgName( TCppScope_t scope, TCppIndex_t imeth, TCppIndex_t iarg );
diff --git a/bindings/pyroot/src/RootWrapper.cxx b/bindings/pyroot/src/RootWrapper.cxx
index 0e136978ab5f353b89c785e443648d48e175b6ec..d87985ac567d3f466cf4738e17775356d896ac07 100644
--- a/bindings/pyroot/src/RootWrapper.cxx
+++ b/bindings/pyroot/src/RootWrapper.cxx
@@ -789,6 +789,11 @@ PyObject* PyROOT::GetCppGlobal( const std::string& name )
       return (PyObject*)MethodProxy_New( name, overloads );
    }
 
+   // Try function templates
+   if (Cppyy::ExistsMethodTemplate(Cppyy::gGlobalScope, name)) {
+      return (PyObject*)TemplateProxy_New(name, CreateScopeProxy(""));
+   }
+
 // allow lookup into std as if global (historic)
    TDataMember* dm = TClass::GetClass( "std" )->GetDataMember( name.c_str() );
    if ( dm ) {
diff --git a/bindings/pyroot/src/TemplateProxy.cxx b/bindings/pyroot/src/TemplateProxy.cxx
index 27773d636c34d055928f90fc9c7c6bd61faace00..5b841a0bc018e81326fde5b1252cc485b46cbc2a 100644
--- a/bindings/pyroot/src/TemplateProxy.cxx
+++ b/bindings/pyroot/src/TemplateProxy.cxx
@@ -9,6 +9,7 @@
 #include "PyCallable.h"
 #include "PyStrings.h"
 #include "Utility.h"
+#include "PyRootType.h"
 
 // ROOT
 #include "TClass.h"
@@ -194,38 +195,6 @@ namespace {
 
    // case 2: non-instantiating obj->method< t0, t1, ... >( a0, a1, ... )
 
-   // build "< type, type, ... >" part of method name
-      PyObject* pyname_v1 = Utility::BuildTemplateName( pytmpl->fPyName, args, 0 );
-      if ( pyname_v1 ) {
-      // lookup method on self (to make sure it propagates), which is readily callable
-         pymeth = PyObject_GetAttr( pytmpl->fSelf ? pytmpl->fSelf : pytmpl->fPyClass, pyname_v1 );
-         if ( pymeth ) { // overloads stop here, as this is an explicit match
-            Py_DECREF( pyname_v1 );
-            return pymeth;         // callable method, next step is by user
-         }
-      }
-      PyErr_Clear();
-
-   // case 3: loop over all previously instantiated templates
-      pymeth = MethodProxy_Type.tp_descr_get(
-         (PyObject*)pytmpl->fTemplated, pytmpl->fSelf, (PyObject*)&MethodProxy_Type );
-      if ( MethodProxy_Check( pymeth ) ) {
-      // now call the method with the arguments
-         PyObject* result = MethodProxy_Type.tp_call( pymeth, args, kwds );
-         Py_DECREF( pymeth ); pymeth = 0;
-         if ( result ) {
-            Py_XDECREF( pyname_v1 );
-            return result;
-         }
-      // TODO: collect error here, as the failure may be either an overload
-      // failure after which we should continue; or a real failure, which should
-      // be reported.
-      }
-      Py_XDECREF( pymeth ); pymeth = 0;
-      PyErr_Clear();
-
-   // still here? try instantiating methods
-
       Bool_t isType = kFALSE;
       Int_t nStrings = 0;
       PyObject* tpArgs = PyTuple_New( nArgs );
@@ -274,9 +243,44 @@ namespace {
          Py_XDECREF( pytc );
       }
 
+   // build "< type, type, ... >" part of method name
+      PyObject* pyname_v1 = Utility::BuildTemplateName( pytmpl->fPyName, args, 0 );
+      if ((isType || nStrings == nArgs) && pyname_v1) {  // types in args or all strings
+      // lookup method on self (to make sure it propagates), which is readily callable
+         pymeth = PyObject_GetAttr( pytmpl->fSelf ? pytmpl->fSelf : pytmpl->fPyClass, pyname_v1 );
+         if ( pymeth ) { // overloads stop here, as this is an explicit match
+            Py_DECREF( pyname_v1 );
+            return pymeth;         // callable method, next step is by user
+         }
+      }
+      PyErr_Clear();
+
+   // case 3: loop over all previously instantiated templates
+      pymeth = MethodProxy_Type.tp_descr_get(
+         (PyObject*)pytmpl->fTemplated, pytmpl->fSelf, (PyObject*)&MethodProxy_Type );
+      if ( MethodProxy_Check( pymeth ) ) {
+      // now call the method with the arguments
+         PyObject* result = MethodProxy_Type.tp_call( pymeth, args, kwds );
+         Py_DECREF( pymeth ); pymeth = 0;
+         if ( result ) {
+            Py_XDECREF( pyname_v1 );
+            return result;
+         }
+      // TODO: collect error here, as the failure may be either an overload
+      // failure after which we should continue; or a real failure, which should
+      // be reported.
+      }
+      Py_XDECREF( pymeth ); pymeth = 0;
+      PyErr_Clear();
+
+   // still here? try instantiating methods
+
       PyObject* clName = PyObject_GetAttr( pytmpl->fPyClass, PyStrings::gCppName );
       if ( ! clName ) clName = PyObject_GetAttr( pytmpl->fPyClass, PyStrings::gName );
-      TClass* klass = TClass::GetClass( PyROOT_PyUnicode_AsString( clName ) );
+      auto clNameStr = std::string(PyROOT_PyUnicode_AsString(clName));
+      if (clNameStr == "_global_cpp")
+         clNameStr = ""; // global namespace
+      TClass* klass = TClass::GetClass(clNameStr.c_str());
       Py_DECREF( clName );
       const std::string& tmplname = pytmpl->fNonTemplated->fMethodInfo->fName;
 
@@ -288,23 +292,23 @@ namespace {
             Py_DECREF( pyname_v2 );
             std::string proto = mname.substr( 1, mname.size() - 2 );
          // the following causes instantiation as necessary
-            TMethod* cppmeth = klass ? klass->GetMethodWithPrototype( tmplname.c_str(), proto.c_str() ) : 0;
+            auto scope = Cppyy::GetScope(clNameStr);
+            auto cppmeth = Cppyy::GetMethodTemplate(scope, tmplname, proto);
             if ( cppmeth ) {    // overload stops here
                Py_XDECREF( pyname_v1 );
-               Cppyy::TCppScope_t scope = Cppyy::GetScope( klass->GetName() );
-               if ( (klass->Property() & kIsNamespace) || (cppmeth->Property() & kIsStatic) ) {
-                  pytmpl->fTemplated->AddMethod( new TFunctionHolder( scope, (Cppyy::TCppMethod_t)cppmeth ) );
+               if (Cppyy::IsNamespace(scope) || Cppyy::IsStaticMethod(cppmeth)) {
+                  pytmpl->fTemplated->AddMethod( new TFunctionHolder( scope, cppmeth ) );
                   pymeth = (PyObject*)MethodProxy_New(
-                     cppmeth->GetName(), new TFunctionHolder( scope, (Cppyy::TCppMethod_t)cppmeth ) );
+                     Cppyy::GetMethodName(cppmeth).c_str(), new TFunctionHolder( scope, cppmeth ) );
                } else {
-                  pytmpl->fTemplated->AddMethod( new TMethodHolder( scope, (Cppyy::TCppMethod_t)cppmeth ) );
+                  pytmpl->fTemplated->AddMethod( new TMethodHolder( scope, cppmeth ) );
                   pymeth = (PyObject*)MethodProxy_New(
-                     cppmeth->GetName(), new TMethodHolder( scope, (Cppyy::TCppMethod_t)cppmeth ) );
+                     Cppyy::GetMethodName(cppmeth).c_str(), new TMethodHolder( scope, cppmeth ) );
                }
-               PyObject_SetAttrString( pytmpl->fPyClass, (char*)cppmeth->GetName(), (PyObject*)pymeth );
+               PyObject_SetAttrString( pytmpl->fPyClass, (char*)Cppyy::GetMethodName(cppmeth).c_str(), (PyObject*)pymeth );
                Py_DECREF( pymeth );
                pymeth = PyObject_GetAttrString(
-                  pytmpl->fSelf ? pytmpl->fSelf : pytmpl->fPyClass, (char*)cppmeth->GetName() );
+                  pytmpl->fSelf ? pytmpl->fSelf : pytmpl->fPyClass, (char*)Cppyy::GetMethodName(cppmeth).c_str() );
                PyObject* result = MethodProxy_Type.tp_call( pymeth, args, kwds );
                Py_DECREF( pymeth );
                return result;