diff --git a/Control/AthenaMonitoring/python/ExampleMonitorAlgorithm.py b/Control/AthenaMonitoring/python/ExampleMonitorAlgorithm.py
index d4ebec701dc1f21fec182bc9e58450c2ed6bb648..5b3c56b6b4d14cc1a5545bb095119801a46c5606 100644
--- a/Control/AthenaMonitoring/python/ExampleMonitorAlgorithm.py
+++ b/Control/AthenaMonitoring/python/ExampleMonitorAlgorithm.py
@@ -85,8 +85,11 @@ def ExampleMonitoringConfig(inputFlags):
                             xbins=[0,.1,.2,.4,.8,1.6])
     myGroup.defineHistogram('random,pT', type='TH2F', title='title;x;y',path='ToBringThemAll',
                             xbins=[0,.1,.2,.4,.8,1.6],ybins=[0,10,30,40,60,70,90])
-    # myGroup.defineHistogram('pT_passed,pT',type='TEfficiency',title='Test TEfficiency;x;Eff',
-    #                         path='AndInTheDarkness',xbins=100,xmin=0.0,xmax=50.0)
+    myGroup.defineHistogram('pT_passed,pT', type='TEfficiency', title='Test TEfficiency;x;Eff',
+                            path='AndInTheDarkness', xbins=100, xmin=0.0, xmax=50.0)
+    myGroup.defineHistogram('pT_passed,pT,random', type='TEfficiency', title='Test TEfficiency 2D;x;y;Eff',
+                            path='AndInTheDarkness', xbins=100, xmin=0.0, xmax=50.0,
+                            ybins=10, ymin=0.0, ymax=2.0)
 
     anotherGroup.defineHistogram('lbWithFilter',title='Lumi;lb;Events',
                                  path='top',xbins=1000,xmin=-0.5,xmax=999.5)
diff --git a/Control/AthenaMonitoringKernel/AthenaMonitoringKernel/HistogramDef.h b/Control/AthenaMonitoringKernel/AthenaMonitoringKernel/HistogramDef.h
index 129c89a852fd17fa9c40f0452977369314be8ba3..3322c7878a83b857a714c1f6313d113a4bb729ad 100644
--- a/Control/AthenaMonitoringKernel/AthenaMonitoringKernel/HistogramDef.h
+++ b/Control/AthenaMonitoringKernel/AthenaMonitoringKernel/HistogramDef.h
@@ -38,6 +38,7 @@ namespace Monitored {
     std::vector<double> yarray; //!< array of y bin edges
 
     std::string zvar; //!< name of z variable
+    int zbins; //!< number of z bins
     float zmin; //!< z axis minimum
     float zmax; //!< z axis maximum
     std::vector<std::string> zlabels; //!< labels for z axis
diff --git a/Control/AthenaMonitoringKernel/python/GenericMonitoringTool.py b/Control/AthenaMonitoringKernel/python/GenericMonitoringTool.py
index 1cc0829922b6915c414f2dc3ed5a89de5754dab5..5b94c9c318fa5d65f0be34d8dc17db4c0172af9c 100644
--- a/Control/AthenaMonitoringKernel/python/GenericMonitoringTool.py
+++ b/Control/AthenaMonitoringKernel/python/GenericMonitoringTool.py
@@ -123,8 +123,8 @@ def defineHistogram(varname, type='TH1F', path=None,
     stringSettingsKeys = ['xvar', 'yvar', 'zvar', 'type', 'path', 'title', 'weight',
     'opt', 'convention', 'alias'] 
     # All of these fileds default to 0
-    numberSettingsKeys = ['xbins', 'xmin', 'xmax', 'ybins', 'ymin', 'ymax', 'zmin',
-    'zmax']
+    numberSettingsKeys = ['xbins', 'xmin', 'xmax', 'ybins', 'ymin', 'ymax', 'zbins',
+    'zmin', 'zmax']
     # All of these fields default to an empty array
     arraySettingsKeys = ['allvars', 'xlabels', 'xarray', 'ylabels', 'yarray', 'zlabels']
     # Initialize a dictionary with all possible fields
diff --git a/Control/AthenaMonitoringKernel/share/GenericMon.txt b/Control/AthenaMonitoringKernel/share/GenericMon.txt
index fe9bb005a08c4c6decdcd62dd25fb161522311ec..3059d7b083de428feb3c255977e623ee2918df80 100644
--- a/Control/AthenaMonitoringKernel/share/GenericMon.txt
+++ b/Control/AthenaMonitoringKernel/share/GenericMon.txt
@@ -10,18 +10,17 @@ ApplicationMgr.ExtSvc += { "THistSvc/THistSvc" };
 AuditorSvc.Auditors  += { "AlgContextAuditor"};
 StoreGateSvc.OutputLevel = 5;
 StoreGateSvc.ActivateHistory = false;
-MessageSvc.useColors        = false;
+MessageSvc.useColors = false;
 THistSvc.OutputLevel = 0;
 THistSvc.Output= {"EXPERT DATAFILE='expert-monitoring.root' OPT='RECREATE'" };
 ToolSvc.MonTool.OutputLevel = 0;
 ToolSvc.MonTool.HistPath="TestGroup";
-// '{"alias": "Eta", "allvars": ["Eta"], "convention": "", "opt": "", "path": "EXPERT", "title": "#eta of Clusters; #eta; number of RoIs", "type": "TH1F", "weight": "", "xarray": [], "xbins": 2, "xlabels": [], "xmax": 2.5, "xmin": -2.5, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
-ToolSvc.MonTool.Histograms =  {'{"alias": "Eta", "allvars": ["Eta"], "convention": "", "opt": "", "path": "EXPERT", "title": "#eta of Clusters; #eta; number of RoIs", "type": "TH1F", "weight": "", "xarray": [], "xbins": 2, "xlabels": [], "xmax": 2.50, "xmin": -2.50, "xvar": "Eta", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
-ToolSvc.MonTool.Histograms += {'{"alias": "Phi", "allvars": ["Phi"], "convention": "", "opt": "", "path": "EXPERT", "title": "#phi of Clusters; #phi; number of RoIs", "type": "TH1F", "weight": "", "xarray": [], "xbins": 2, "xlabels": [], "xmax": 3.15, "xmin": -3.15, "xvar": "Phi", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
-ToolSvc.MonTool.Histograms += {'{"alias": "Eta_vs_Phi", "allvars": ["Eta", "Phi"], "convention": "", "opt": "", "path": "EXPERT", "title": "#eta vs #phi of Clusters; #eta; #phi; number of RoIs", "type": "TH2F", "weight": "", "xarray": [], "xbins": 2, "xlabels": [], "xmax": 2.5, "xmin": -2.5, "xvar": "Eta", "yarray": [], "ybins": 2, "ylabels": [], "ymax": 3.15, "ymin": -3.15, "yvar": "Phi", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
-ToolSvc.MonTool.Histograms += {'{"alias": "TIME_t1", "allvars": ["TIME_t1"], "convention": "", "opt": "", "path": "EXPERT", "title": "Timing of tool 1", "type": "TH1F", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1000.0, "xmin": 0.0, "xvar": "TIME_t1", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
-ToolSvc.MonTool.Histograms += {'{"alias": "TIME_t2", "allvars": ["TIME_t2"], "convention": "", "opt": "", "path": "EXPERT", "title": "Timing of tool 2", "type": "TH1F", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1000.0, "xmin": 0.0, "xvar": "TIME_t2", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
-ToolSvc.MonTool.Histograms += {'{"alias": "DetID", "allvars": ["DetID"], "convention": "", "opt": "", "path": "EXPERT", "title": "Test of text filling", "type": "TH1F", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "DetID", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
-ToolSvc.MonTool.Histograms += {'{"alias": "DetCalo_vs_DetID", "allvars": ["DetCalo", "DetID"], "convention": "", "opt": "", "path": "EXPERT", "title": "Fill 2D with strings", "type": "TH2I", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "DetCalo", "yarray": [], "ybins": 10, "ylabels": [], "ymax": 10.0, "ymin": 0.0, "yvar": "DetID", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
-ToolSvc.MonTool.Histograms += {'{"alias": "DetCalo_vs_y", "allvars": ["DetCalo", "y"], "convention": "", "opt": "", "path": "EXPERT", "title": "Fill 2D with string & double", "type": "TH2I", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "DetCalo", "yarray": [], "ybins": 10, "ylabels": [], "ymax": 10.0, "ymin": 0.0, "yvar": "y", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
-ToolSvc.MonTool.Histograms += {'{"alias": "x_vs_DetCalo", "allvars": ["x", "DetCalo"], "convention": "", "opt": "", "path": "EXPERT", "title": "Fill 2D with double & string", "type": "TH2I", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "x", "yarray": [], "ybins": 10, "ylabels": [], "ymax": 10.0, "ymin": 0.0, "yvar": "DetCalo", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
+ToolSvc.MonTool.Histograms =  {'{"alias": "Eta", "allvars": ["Eta"], "convention": "", "opt": "", "path": "EXPERT", "title": "#eta of Clusters; #eta; number of RoIs", "type": "TH1F", "weight": "", "xarray": [], "xbins": 2, "xlabels": [], "xmax": 2.50, "xmin": -2.50, "xvar": "Eta", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
+ToolSvc.MonTool.Histograms += {'{"alias": "Phi", "allvars": ["Phi"], "convention": "", "opt": "", "path": "EXPERT", "title": "#phi of Clusters; #phi; number of RoIs", "type": "TH1F", "weight": "", "xarray": [], "xbins": 2, "xlabels": [], "xmax": 3.15, "xmin": -3.15, "xvar": "Phi", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
+ToolSvc.MonTool.Histograms += {'{"alias": "Eta_vs_Phi", "allvars": ["Eta", "Phi"], "convention": "", "opt": "", "path": "EXPERT", "title": "#eta vs #phi of Clusters; #eta; #phi; number of RoIs", "type": "TH2F", "weight": "", "xarray": [], "xbins": 2, "xlabels": [], "xmax": 2.5, "xmin": -2.5, "xvar": "Eta", "yarray": [], "ybins": 2, "ylabels": [], "ymax": 3.15, "ymin": -3.15, "yvar": "Phi", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
+ToolSvc.MonTool.Histograms += {'{"alias": "TIME_t1", "allvars": ["TIME_t1"], "convention": "", "opt": "", "path": "EXPERT", "title": "Timing of tool 1", "type": "TH1F", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1000.0, "xmin": 0.0, "xvar": "TIME_t1", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
+ToolSvc.MonTool.Histograms += {'{"alias": "TIME_t2", "allvars": ["TIME_t2"], "convention": "", "opt": "", "path": "EXPERT", "title": "Timing of tool 2", "type": "TH1F", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1000.0, "xmin": 0.0, "xvar": "TIME_t2", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
+ToolSvc.MonTool.Histograms += {'{"alias": "DetID", "allvars": ["DetID"], "convention": "", "opt": "", "path": "EXPERT", "title": "Test of text filling", "type": "TH1F", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "DetID", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
+ToolSvc.MonTool.Histograms += {'{"alias": "DetCalo_vs_DetID", "allvars": ["DetCalo", "DetID"], "convention": "", "opt": "", "path": "EXPERT", "title": "Fill 2D with strings", "type": "TH2I", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "DetCalo", "yarray": [], "ybins": 10, "ylabels": [], "ymax": 10.0, "ymin": 0.0, "yvar": "DetID", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
+ToolSvc.MonTool.Histograms += {'{"alias": "DetCalo_vs_y", "allvars": ["DetCalo", "y"], "convention": "", "opt": "", "path": "EXPERT", "title": "Fill 2D with string & double", "type": "TH2I", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "DetCalo", "yarray": [], "ybins": 10, "ylabels": [], "ymax": 10.0, "ymin": 0.0, "yvar": "y", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
+ToolSvc.MonTool.Histograms += {'{"alias": "x_vs_DetCalo", "allvars": ["x", "DetCalo"], "convention": "", "opt": "", "path": "EXPERT", "title": "Fill 2D with double & string", "type": "TH2I", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "x", "yarray": [], "ybins": 10, "ylabels": [], "ymax": 10.0, "ymin": 0.0, "yvar": "DetCalo", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'};
diff --git a/Control/AthenaMonitoringKernel/src/HistogramDef.cxx b/Control/AthenaMonitoringKernel/src/HistogramDef.cxx
index 91e4a8009098bf7187b9841c6296c6acc153ee1d..cf6cb46fbda4e3652dcb272fd5da18f5d5c9795e 100644
--- a/Control/AthenaMonitoringKernel/src/HistogramDef.cxx
+++ b/Control/AthenaMonitoringKernel/src/HistogramDef.cxx
@@ -36,6 +36,7 @@ const HistogramDef HistogramDef::parse(const std::string& histogramDefinition) {
   result.yarray = setting["yarray"].get<std::vector<double>>();
 
   result.zvar = setting["zvar"];
+  result.zbins = setting["zbins"];
   result.zmin = setting["zmin"];
   result.zmax = setting["zmax"];
   result.zlabels = setting["zlabels"].get<std::vector<std::string>>();
diff --git a/Control/AthenaMonitoringKernel/src/HistogramFiller/HistogramFactory.cxx b/Control/AthenaMonitoringKernel/src/HistogramFiller/HistogramFactory.cxx
index 1f7a616041c8b93f2db30e8e5ce9eb8bd8622a98..fdf06594ee54a0810a3c7eaca5ed5a5e49cffc06 100644
--- a/Control/AthenaMonitoringKernel/src/HistogramFiller/HistogramFactory.cxx
+++ b/Control/AthenaMonitoringKernel/src/HistogramFiller/HistogramFactory.cxx
@@ -135,7 +135,16 @@ TEfficiency* HistogramFactory::createEfficiency(const HistogramDef& def) {
   // Hold global lock until we have detached object from gDirectory
   {
     std::scoped_lock<std::mutex> dirLock(s_histDirMutex);
-    e = new TEfficiency(def.alias.c_str(),def.title.c_str(),def.xbins,def.xmin,def.xmax);
+    if (def.ybins==0 && def.zbins==0) { // 1D TEfficiency
+      e = new TEfficiency(def.alias.c_str(), def.title.c_str(),
+        def.xbins, def.xmin, def.xmax);
+    } else if (def.ybins>0 && def.zbins==0) { // 2D TEfficiency
+      e = new TEfficiency(def.alias.c_str(), def.title.c_str(),
+        def.xbins, def.xmin, def.xmax, def.ybins, def.ymin, def.ymax);
+    } else if (def.ybins>0 && def.zbins>0) { // 3D TEfficiency
+      e = new TEfficiency(def.alias.c_str(), def.title.c_str(),
+        def.xbins, def.xmin, def.xmax, def.ybins, def.ymin, def.ymax, def.zbins, def.zmin, def.zmax);
+    }
     e->SetDirectory(0);
   }
   if ( !m_histSvc->regEfficiency(fullName,e) ) {
@@ -145,9 +154,11 @@ TEfficiency* HistogramFactory::createEfficiency(const HistogramDef& def) {
   TH1* total ATLAS_THREAD_SAFE = const_cast<TH1*>(e->GetTotalHistogram());
   setLabels(total->GetXaxis(), def.xlabels);
   setLabels(total->GetYaxis(), def.ylabels);
+  setLabels(total->GetZaxis(), def.zlabels);
   TH1* passed ATLAS_THREAD_SAFE = const_cast<TH1*>(e->GetPassedHistogram());
   setLabels(passed->GetXaxis(), def.xlabels);
   setLabels(passed->GetYaxis(), def.ylabels);
+  setLabels(passed->GetZaxis(), def.zlabels);
 
   return e;
 }
diff --git a/Control/AthenaMonitoringKernel/src/HistogramFiller/HistogramFiller1D.h b/Control/AthenaMonitoringKernel/src/HistogramFiller/HistogramFiller1D.h
index a84b743f478df1f0d31e63d92641b070efa1e1a7..2fece6ef8a598e50c3344c44ca278e91cc7f0c97 100644
--- a/Control/AthenaMonitoringKernel/src/HistogramFiller/HistogramFiller1D.h
+++ b/Control/AthenaMonitoringKernel/src/HistogramFiller/HistogramFiller1D.h
@@ -30,18 +30,18 @@ namespace Monitored {
       std::function<double(size_t)> weightValue = [] (size_t ){ return 1.0; };  // default is always 1.0
       std::vector<double> weightVector;
       if ( m_monWeight != nullptr ) {
-	weightVector = m_monWeight->getVectorRepresentation();
-	weightValue = [&](size_t i){ return weightVector[i]; };
+        weightVector = m_monWeight->getVectorRepresentation();
+        weightValue = [&](size_t i){ return weightVector[i]; };
       }
 
       if ( not m_monVariables.at(0).get().hasStringRepresentation() ) {
-	const auto valuesVector = m_monVariables.at(0).get().getVectorRepresentation();
-	fill( std::size( valuesVector), [&](size_t i){ return valuesVector[i]; }, weightValue );
-	return std::size( valuesVector );
+        const auto valuesVector = m_monVariables.at(0).get().getVectorRepresentation();
+        fill( std::size( valuesVector), [&](size_t i){ return valuesVector[i]; }, weightValue );
+        return std::size( valuesVector );
       } else {
-	const auto valuesVector = m_monVariables.at(0).get().getStringVectorRepresentation();
-	fill( std::size( valuesVector ), [&](size_t i){ return valuesVector[i].c_str(); }, weightValue );
-	return std::size( valuesVector );
+        const auto valuesVector = m_monVariables.at(0).get().getStringVectorRepresentation();
+        fill( std::size( valuesVector ), [&](size_t i){ return valuesVector[i].c_str(); }, weightValue );
+        return std::size( valuesVector );
       }
     }
 
@@ -53,7 +53,7 @@ namespace Monitored {
 
       auto histogram = this->histogram<TH1>();
       for ( size_t i = 0; i < n; ++i ) {
-	histogram->Fill( f1(i), f2(i) );
+        histogram->Fill( f1(i), f2(i) );
       }
     }
   };
diff --git a/Control/AthenaMonitoringKernel/src/HistogramFiller/HistogramFillerEfficiency.h b/Control/AthenaMonitoringKernel/src/HistogramFiller/HistogramFillerEfficiency.h
index ed0eae87ee9ca2e91c9cfe05cc92568f2bb5802e..c0cec043768c18a505fe9fce7696b573d9af6b5f 100644
--- a/Control/AthenaMonitoringKernel/src/HistogramFiller/HistogramFillerEfficiency.h
+++ b/Control/AthenaMonitoringKernel/src/HistogramFiller/HistogramFillerEfficiency.h
@@ -24,32 +24,68 @@ namespace Monitored {
     }
 
     virtual unsigned fill() override {
-      if (m_monVariables.size() != 2) {
+      auto efficiency = this->histogram<TEfficiency>();
+      std::lock_guard<std::mutex> lock(*(this->m_mutex));
+
+      int nMonVar = m_monVariables.size();
+      if ( nMonVar==2 ) { // Single observable (1D TEfficiency)
+        auto valuesVector0 = m_monVariables[0].get().getVectorRepresentation();
+        auto valuesVector1 = retrieveVariable(efficiency, 1);
+        for (unsigned i = 0; i < std::size(valuesVector0); ++i) {
+          efficiency->Fill(valuesVector0[i], valuesVector1[i]);
+        }
+        return std::size(valuesVector0);
+      } else if ( nMonVar==3 ) { // Two observables (2D TEfficiency)
+        auto valuesVector0 = m_monVariables[0].get().getVectorRepresentation();
+        auto valuesVector1 = retrieveVariable(efficiency, 1);
+        auto valuesVector2 = retrieveVariable(efficiency, 2);
+        for (unsigned i = 0; i < std::size(valuesVector0); ++i) {
+          efficiency->Fill(valuesVector0[i], valuesVector1[i], valuesVector2[i]);
+        }
+        return std::size(valuesVector0);
+      } else if ( nMonVar==4 ) { // Three observables (3D Efficiency)
+        auto valuesVector0 = m_monVariables[0].get().getVectorRepresentation();
+        auto valuesVector1 = retrieveVariable(efficiency, 1);
+        auto valuesVector2 = retrieveVariable(efficiency, 2);
+        auto valuesVector3 = retrieveVariable(efficiency, 3);
+        for (unsigned i = 0; i < std::size(valuesVector0); ++i) {
+          efficiency->Fill(valuesVector0[i], valuesVector1[i], valuesVector2[i], valuesVector3[i]);
+        }
+        return std::size(valuesVector0);
+      } else {
         return 0;
       }
+    }
 
-      auto histogram = this->histogram<TEfficiency>();
-      auto valuesVector1 = m_monVariables[0].get().getVectorRepresentation();
-      auto valuesVector2 = m_monVariables[1].get().getVectorRepresentation();
-
-      std::lock_guard<std::mutex> lock(*(this->m_mutex));
-
-      if ( m_monVariables.at(1).get().hasStringRepresentation() ) {
-	valuesVector2.clear();
-	TH1* tot ATLAS_THREAD_SAFE  = const_cast<TH1*>(histogram->GetTotalHistogram());
-	const TAxis* xaxis = tot->GetXaxis();
-	for ( const std::string& value: m_monVariables[1].get().getStringVectorRepresentation() ) {
-	  const int binNumber = xaxis->FindFixBin( value.c_str() );
-	  const double binCenter ATLAS_THREAD_SAFE  = xaxis->GetBinCenter( binNumber );
-	  valuesVector2.push_back(binCenter);
-	}
+    const std::vector<double> retrieveVariable(TEfficiency* efficiency, int iVariable) {
+      auto valueVariable = m_monVariables[iVariable];
+      auto valuesVector = valueVariable.get().getVectorRepresentation();
+      if ( valueVariable.get().hasStringRepresentation() ) {
+        valuesVector.clear();
+        TH1* tot ATLAS_THREAD_SAFE  = const_cast<TH1*>(efficiency->GetTotalHistogram());
+        const TAxis* axis = getAxis(tot, iVariable);
+        for ( const std::string& value : valueVariable.get().getStringVectorRepresentation() ) {
+          const int binNumber = axis->FindFixBin( value.c_str() );
+          const double binCenter ATLAS_THREAD_SAFE = axis->GetBinCenter(binNumber);
+          valuesVector.push_back(binCenter);
+        }
       }
+      return valuesVector;
+    }
 
-      for (unsigned i = 0; i < std::size(valuesVector1); ++i) {
-	histogram->Fill(valuesVector1[i],valuesVector2[i]);
+    const TAxis* getAxis(TH1* hist, int iAxis) {
+      if ( iAxis==1 ) {
+        return hist->GetXaxis();
+      } else if ( iAxis==2 ) {
+        return hist->GetYaxis();
+      } else if ( iAxis==3 ) {
+        return hist->GetZaxis();
+      } else {
+        HistogramException("Invalid request for axis when defining TEfficiency.");
+        return nullptr;
       }
-      return std::size(valuesVector1);
     }
+
   };
 }
 
diff --git a/Control/AthenaMonitoringKernel/test/GenericMonParsing_test.cxx b/Control/AthenaMonitoringKernel/test/GenericMonParsing_test.cxx
index 14eb2a19a840b024a463314abc0beb569ffea11a..f509681bb7837723cdec5c48726c2d44cf87f727 100644
--- a/Control/AthenaMonitoringKernel/test/GenericMonParsing_test.cxx
+++ b/Control/AthenaMonitoringKernel/test/GenericMonParsing_test.cxx
@@ -35,6 +35,7 @@ json defaultJson() {
   j["ymax"] = 0.0;
   j["ymin"] = 0.0;
   j["yvar"] = "";
+  j["zbins"] = 0;
   j["zlabels"] = json::array();
   j["zmax"] = 0.0;
   j["zmin"] = 0.0;
diff --git a/Control/AthenaMonitoringKernel/test/HistogramFactoryTestSuite.cxx b/Control/AthenaMonitoringKernel/test/HistogramFactoryTestSuite.cxx
index 5decb904fecc650ca19ba445985e2137d922e342..97f9f23983ca81c898cbdd4550ffd2e2e022bb0b 100644
--- a/Control/AthenaMonitoringKernel/test/HistogramFactoryTestSuite.cxx
+++ b/Control/AthenaMonitoringKernel/test/HistogramFactoryTestSuite.cxx
@@ -116,9 +116,9 @@ class HistogramFactoryTestSuite {
     }
 
     void test_shouldRegisterAndReturnTEfficiencyHistogram() {
-      TEfficiency* const graph = createHistogram<TEfficiency>("TEfficiency");
-      // VALUE(m_histSvc->exists("/HistogramFactoryTestSuite/TEfficiency")) EXPECTED(true);
-      VALUE(graph) NOT_EXPECTED(nullptr);
+      TEfficiency* const efficiency = createHistogram<TEfficiency>("TEfficiency");
+      VALUE(m_histSvc->existsEfficiency("/HistogramFactoryTestSuite/TEfficiency")) EXPECTED(true);
+      VALUE(efficiency) NOT_EXPECTED(nullptr);
     }
 
     void test_shouldThrowExceptionForUnknownHistogramType() {
@@ -283,6 +283,10 @@ class HistogramFactoryTestSuite {
       for (string graphName : m_histSvc->getGraphs()) {
         m_histSvc->deReg(graphName);
       }
+
+      for (string efficiencyName : m_histSvc->getEfficiencies()) {
+        m_histSvc->deReg(efficiencyName);
+      }
     }
 
   // ==================== Initialization & run ====================
diff --git a/Control/AthenaMonitoringKernel/test/test_defineHistogram.py b/Control/AthenaMonitoringKernel/test/test_defineHistogram.py
index 6b13dbc3cb372a6fdef7b9f142ad20345ad571fb..60864e4468001afe97b04d61c84220345ff1bd26 100644
--- a/Control/AthenaMonitoringKernel/test/test_defineHistogram.py
+++ b/Control/AthenaMonitoringKernel/test/test_defineHistogram.py
@@ -11,68 +11,68 @@ from AthenaMonitoringKernel.GenericMonitoringTool import defineHistogram
 class Test( unittest.TestCase ):
    def test_1D( self ):
       check = defineHistogram('var', 'TH1F', 'EXPERT', 'title', '', '', 10, 0.0, 10.0)
-      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "", "path": "EXPERT", "title": "title", "type": "TH1F", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
+      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "", "path": "EXPERT", "title": "title", "type": "TH1F", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
       self.assertEqual(json.loads(check), json.loads(true))
 
    def test_1D_opt( self ):
       check = defineHistogram('var', opt='myopt')
-      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "myopt", "path": "", "title": "var", "type": "TH1F", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
+      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "myopt", "path": "", "title": "var", "type": "TH1F", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
       self.assertEqual(json.loads(check), json.loads(true))
 
    def test_1D_weight( self ):
       check = defineHistogram('var', weight='myweight')
-      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "", "path": "", "title": "var", "type": "TH1F", "weight": "myweight", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
+      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "", "path": "", "title": "var", "type": "TH1F", "weight": "myweight", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
       self.assertEqual(json.loads(check), json.loads(true))
 
    def test_1D_array( self ):
       check = defineHistogram('var', xbins=[0, 1, 2, 4, 8])
-      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "", "path": "", "title": "var", "type": "TH1F", "weight": "", "xarray": [0, 1, 2, 4, 8], "xbins": 4, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
+      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "", "path": "", "title": "var", "type": "TH1F", "weight": "", "xarray": [0, 1, 2, 4, 8], "xbins": 4, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
       self.assertEqual(json.loads(check), json.loads(true))
 
    def test_1D_title( self ):
       check = defineHistogram('var', title='mytitle')
-      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "", "path": "", "title": "mytitle", "type": "TH1F", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
+      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "", "path": "", "title": "mytitle", "type": "TH1F", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
       self.assertEqual(json.loads(check), json.loads(true))
 
    def test_1D_labelsX( self ):
       check = defineHistogram('var', xlabels=["bin0", "bin1"])
-      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "", "path": "", "title": "var", "type": "TH1F", "weight": "", "xarray": [], "xbins": 2, "xlabels": ["bin0", "bin1"], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
+      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "", "path": "", "title": "var", "type": "TH1F", "weight": "", "xarray": [], "xbins": 2, "xlabels": ["bin0", "bin1"], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
       self.assertEqual(json.loads(check), json.loads(true))
 
    def test_1D_labelsY( self ):
       check = defineHistogram('var', ylabels=["bin0", "bin1"])
-      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "", "path": "", "title": "var", "type": "TH1F", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 2, "ylabels": ["bin0", "bin1"], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
+      true = '{"alias": "var", "allvars": ["var"], "convention": "", "opt": "", "path": "", "title": "var", "type": "TH1F", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 2, "ylabels": ["bin0", "bin1"], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
       self.assertEqual(json.loads(check), json.loads(true))
 
    def test_2D( self ):
       check = defineHistogram('varX,varY', type='TH2F', xbins=10, xmin=0.0, xmax=10.0, ybins=40, ymin=0.0, ymax=20.0)
-      true = '{"alias": "varX_vs_varY", "allvars": ["varX", "varY"], "convention": "", "opt": "", "path": "", "title": "varX,varY", "type": "TH2F", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "varX", "yarray": [], "ybins": 40, "ylabels": [], "ymax": 20.0, "ymin": 0.0, "yvar": "varY", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
+      true = '{"alias": "varX_vs_varY", "allvars": ["varX", "varY"], "convention": "", "opt": "", "path": "", "title": "varX,varY", "type": "TH2F", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "varX", "yarray": [], "ybins": 40, "ylabels": [], "ymax": 20.0, "ymin": 0.0, "yvar": "varY", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
       self.assertEqual(json.loads(check), json.loads(true))
 
    def test_2D_array( self ):
       check = defineHistogram('varX,varY', 'TH2F', xbins=[0,1,2], ybins=[1,2,3,7])
-      true = '{"alias": "varX_vs_varY", "allvars": ["varX", "varY"], "convention": "", "opt": "", "path": "", "title": "varX,varY", "type": "TH2F", "weight": "", "xarray": [0, 1, 2], "xbins": 2, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "varX", "yarray": [1, 2, 3, 7], "ybins": 3, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "varY", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
+      true = '{"alias": "varX_vs_varY", "allvars": ["varX", "varY"], "convention": "", "opt": "", "path": "", "title": "varX,varY", "type": "TH2F", "weight": "", "xarray": [0, 1, 2], "xbins": 2, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "varX", "yarray": [1, 2, 3, 7], "ybins": 3, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "varY", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
       self.assertEqual(json.loads(check), json.loads(true))
 
    def test_2D_labelsXY( self ):
       check = defineHistogram('varX,varY', 'TH2F', xlabels=["bin0", "bin1"], ylabels=["bin0", "bin1", "bin2"])
-      true = '{"alias": "varX_vs_varY", "allvars": ["varX", "varY"], "convention": "", "opt": "", "path": "", "title": "varX,varY", "type": "TH2F", "weight": "", "xarray": [], "xbins": 2, "xlabels": ["bin0", "bin1"], "xmax": 1, "xmin": 0, "xvar": "varX", "yarray": [], "ybins": 3, "ylabels": ["bin0", "bin1", "bin2"], "ymax": 0.0, "ymin": 0.0, "yvar": "varY", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
+      true = '{"alias": "varX_vs_varY", "allvars": ["varX", "varY"], "convention": "", "opt": "", "path": "", "title": "varX,varY", "type": "TH2F", "weight": "", "xarray": [], "xbins": 2, "xlabels": ["bin0", "bin1"], "xmax": 1, "xmin": 0, "xvar": "varX", "yarray": [], "ybins": 3, "ylabels": ["bin0", "bin1", "bin2"], "ymax": 0.0, "ymin": 0.0, "yvar": "varY", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
       self.assertEqual(json.loads(check), json.loads(true))
 
    def test_3D( self ):
       check = defineHistogram('varX,varY,varZ', 'TProfile2D',
          xbins=10, xmin=0.0, xmax=10.0, ybins=40, ymin=0.0, ymax=20.0, zmin=-1.0, zmax=1.0)
-      true = '{"alias": "varX_vs_varY_vs_varZ", "allvars": ["varX", "varY", "varZ"], "convention": "", "opt": "", "path": "", "title": "varX,varY,varZ", "type": "TProfile2D", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "varX", "yarray": [], "ybins": 40, "ylabels": [], "ymax": 20.0, "ymin": 0.0, "yvar": "varY", "zlabels": [], "zmax": 1.0, "zmin": -1.0, "zvar": "varZ"}'
+      true = '{"alias": "varX_vs_varY_vs_varZ", "allvars": ["varX", "varY", "varZ"], "convention": "", "opt": "", "path": "", "title": "varX,varY,varZ", "type": "TProfile2D", "weight": "", "xarray": [], "xbins": 10, "xlabels": [], "xmax": 10.0, "xmin": 0.0, "xvar": "varX", "yarray": [], "ybins": 40, "ylabels": [], "ymax": 20.0, "ymin": 0.0, "yvar": "varY", "zbins": 0, "zlabels": [], "zmax": 1.0, "zmin": -1.0, "zvar": "varZ"}'
       self.assertEqual(json.loads(check), json.loads(true))
 
    def test_efficiency( self ):
       check = defineHistogram('var,pass', type='TEfficiency')
-      true = '{"alias": "var_vs_pass", "allvars": ["var", "pass"], "convention": "", "opt": "", "path": "", "title": "var,pass", "type": "TEfficiency", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "pass", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
+      true = '{"alias": "var_vs_pass", "allvars": ["var", "pass"], "convention": "", "opt": "", "path": "", "title": "var,pass", "type": "TEfficiency", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "pass", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
       self.assertEqual(json.loads(check), json.loads(true))
 
    def test_offlineNamingConvention( self ):
       check = defineHistogram('var', path='EXPERT', convention='OFFLINE:lowStat')
-      true = '{"alias": "var", "allvars": ["var"], "convention": "OFFLINE:lowStat", "opt": "", "path": "EXPERT", "title": "var", "type": "TH1F", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
+      true = '{"alias": "var", "allvars": ["var"], "convention": "OFFLINE:lowStat", "opt": "", "path": "EXPERT", "title": "var", "type": "TH1F", "weight": "", "xarray": [], "xbins": 100, "xlabels": [], "xmax": 1, "xmin": 0, "xvar": "var", "yarray": [], "ybins": 0.0, "ylabels": [], "ymax": 0.0, "ymin": 0.0, "yvar": "", "zbins": 0, "zlabels": [], "zmax": 0.0, "zmin": 0.0, "zvar": ""}'
       self.assertEqual(json.loads(check), json.loads(true))
 
    def test_enforcePath( self ):