diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/CMakeLists.txt b/InnerDetector/InDetValidation/InDetTrackPerfMon/CMakeLists.txt
index 4f4d8354d329b94f338040942bec2062b86bdc2d..63adfeca79f669ee3afd95b3860b61f74e80cf63 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/CMakeLists.txt
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/CMakeLists.txt
@@ -12,7 +12,7 @@ find_package( nlohmann_json )
 
 # Component(s) in the package:
 atlas_add_library( InDetTrackPerfMonLib
-                   src/*.cxx
+                   src/*.cxx src/plots/*.cxx
                    PUBLIC_HEADERS InDetTrackPerfMon
                    PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
                    LINK_LIBRARIES AthenaBaseComps AthenaKernel AthenaMonitoringLib CxxUtils GaudiKernel InDetIdentifier TrkValHistUtils xAODBase xAODEventInfo xAODJet xAODTracking xAODTruth InDetTrackSystematicsToolsLib InDetRecToolInterfaces TrigDecisionToolLib AsgServicesLib 
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/InDetTrackPerfMon/IPlotsDefinitionSvc.h b/InnerDetector/InDetValidation/InDetTrackPerfMon/InDetTrackPerfMon/IPlotsDefinitionSvc.h
index 542e609b438ff5043389cbee0d4d4ed1ad498b8b..1ae80ca74ac98528c4ad6ed4709efe82c4e18b3f 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/InDetTrackPerfMon/IPlotsDefinitionSvc.h
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/InDetTrackPerfMon/IPlotsDefinitionSvc.h
@@ -23,29 +23,28 @@
 
 
 namespace IDTPM {
-
   class SinglePlotDefinition;
+}
 
-  class IPlotsDefinitionSvc :
-      virtual public asg::IAsgService {
 
-  public:
+class IPlotsDefinitionSvc :
+  virtual public asg::IAsgService {
 
-    /// typedef for map definition
-    typedef std::unordered_map< std::string, SinglePlotDefinition > plotsDefMap_t;
+public:
 
-    /// Creates the InterfaceID and interfaceID() method
-    DeclareInterfaceID( IDTPM::IPlotsDefinitionSvc, 1, 0 );
+  /// typedef for map definition
+  typedef std::unordered_map< std::string, IDTPM::SinglePlotDefinition > plotsDefMap_t;
 
-    /// Destructor
-    virtual ~IPlotsDefinitionSvc() = default;
+  /// Creates the InterfaceID and interfaceID() method
+  DeclareInterfaceID( IPlotsDefinitionSvc, 1, 0 );
 
-    /// Get the plot definition
-    virtual const SinglePlotDefinition& definition(
-        const std::string& identifier ) const = 0;
+  /// Destructor
+  virtual ~IPlotsDefinitionSvc() = default;
 
-  }; // class IPlotsDefinitionSvc
+  /// Get the plot definition
+  virtual const IDTPM::SinglePlotDefinition& definition(
+      const std::string& identifier ) const = 0;
 
-} // namespace IDTPM
+}; // class IPlotsDefinitionSvc
 
-#endif // > !INDETTRACKPERFMON_IHISTOGRAMDEFINITIONSVC_H
+#endif // > !INDETTRACKPERFMON_IPLOTSDEFINITIONSVC_H
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/data/PlotsDefCommonValues.json b/InnerDetector/InDetValidation/InDetTrackPerfMon/data/PlotsDefCommonValues.json
new file mode 100644
index 0000000000000000000000000000000000000000..c7bf4ab6133df9a7948892acc9549c4090a6273f
--- /dev/null
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/data/PlotsDefCommonValues.json
@@ -0,0 +1,4 @@
+{
+    "PI"      : [ "3.1415926",    "pi value" ],
+    "ETAMAX"  : [ "2.5",          "eta coverage of the tracker" ]
+}
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/data/PlotsDefFileList_default.txt b/InnerDetector/InDetValidation/InDetTrackPerfMon/data/PlotsDefFileList_default.txt
new file mode 100644
index 0000000000000000000000000000000000000000..eb1ae7a0549d5ea4cc86774eeca8159979dc6bd9
--- /dev/null
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/data/PlotsDefFileList_default.txt
@@ -0,0 +1 @@
+InDetTrackPerfMon/TrkParamPlotsDef.json
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/data/TrkParamPlotsDef.json b/InnerDetector/InDetValidation/InDetTrackPerfMon/data/TrkParamPlotsDef.json
new file mode 100644
index 0000000000000000000000000000000000000000..ecf7af447f977b0ff5fffec6ea9606bd5b5dd957
--- /dev/null
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/data/TrkParamPlotsDef.json
@@ -0,0 +1,12 @@
+{
+    "$TRKTAG_pt" : {
+        "type" : "TH1F",
+        "xAxis" : { "title" : "$TRKTYPE p_{T} [GeV]", "nBins" : "100", "low" : "0.0", "high" : "100.0" },
+        "yAxis" : { "title" : "Entries" }
+    },
+    "$TRKTAG_eta" : {
+        "type" : "TH1F",
+        "xAxis" : { "title" : "$TRKTYPE #eta", "nBins" : "100", "low" : "-$ETAMAX", "high" : "$ETAMAX" },
+        "yAxis" : { "title" : "Entries" }
+    }
+}
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/data/trkAnaConfigs_example.json b/InnerDetector/InDetValidation/InDetTrackPerfMon/data/trkAnaConfigs_example.json
index f2f522b1aaf94bd7bd1a26529423290e5093a6d4..d254133ebc714f8b3c8b9c5f5c3cf67cbd99ec0b 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/data/trkAnaConfigs_example.json
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/data/trkAnaConfigs_example.json
@@ -26,7 +26,7 @@
         "MatchingType"    : "DeltaRMatch",
         "dRmax"           : 0.05,
         "pTResMax"        : -9.9,
-        "doEfficiencies" : false
+        "plotEfficiencies" : false
     },
     "TrkAnaTrigEle" : {
         "enabled" : true,
@@ -39,7 +39,7 @@
         "pTResMax"        : -9.9,
         "SelectOfflineObject" : "Electron", 
         "ObjectQuality"       : "Tight",
-        "doOfflineElectrons" : true
+        "plotOfflineElectrons" : true
     },
     "TrkAnaOffl1" : {
         "enabled" : true,
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/python/ConfigUtils.py b/InnerDetector/InDetValidation/InDetTrackPerfMon/python/ConfigUtils.py
index 7d0951e667a1b7bc07259a53957c4371ac6759f9..3965e769a76ad5f7b67f4344442c36a4bbdef79d 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/python/ConfigUtils.py
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/python/ConfigUtils.py
@@ -32,8 +32,9 @@ def getTrkAnaDicts( flags, input_file, unpackChains=False ):
             analysesDict.update( { trkAnaName : trkAnaDict } )
             ## Update TrkAnalysis tag for this entry
             analysesDict[trkAnaName]["anaTag"] = "_" + trkAnaName
-            ## Update SubFolder for this entry (= trkAnaName if empty)
-            if analysesDict[trkAnaName]["SubFolder"] == "" :
+            ## Update SubFolder for this entry (= trkAnaName if not set or empty)
+            if ( "SubFolder" not in analysesDict[trkAnaName].keys() or
+                 analysesDict[trkAnaName]["SubFolder"] == "" ) :
                 analysesDict[trkAnaName]["SubFolder"] = trkAnaName
             analysesDict[trkAnaName]["SubFolder"] += "/"
             ## Update TrkAnalysis ChainNames to full chain list (not regex)
@@ -106,7 +107,7 @@ def getPlotsDefList( flags ):
     log = logging.getLogger( "getPlotsDefList" )
 
     # open the list of json files
-    log.debug( "plotsDefFileList : ", flags.PhysVal.IDTPM.plotsDefFileList ) 
+    log.debug( "plotsDefFileList : %s", flags.PhysVal.IDTPM.plotsDefFileList ) 
     listPath = find_datafile( flags.PhysVal.IDTPM.plotsDefFileList )
     if listPath is None:
         log.error( "plotsDefFileList not found" )
@@ -115,21 +116,19 @@ def getPlotsDefList( flags ):
     plotsDefFileNames = []
     with open( listPath, "r" ) as input_flist :
         plotsDefFileNames = input_flist.read().splitlines()
-    log.debug( "plotsDefFileNames : ", plotsDefFileNames )
 
     # creating the basic histogrm definition dictionary 
     plotsDefDict = {}
 
     for plotsDefFileName in plotsDefFileNames :
         dataPath = find_datafile( plotsDefFileName )
-        log.debug( "Reading input plots definitions : ", dataPath )
+        log.debug( "Reading input plots definitions : %s", dataPath )
         if dataPath is None:
             log.error( "plotsDefFile %s not found", plotsDefFileName )
             return None
 
         with open( dataPath, "r" ) as input_json_file :
             plotsDefDict.update( json.load( input_json_file ) )
-    log.debug( "Full plots definition dict : ", plotsDefDict )
 
     # Turn all histo definitions into a list of strings
     # each string has a flattened json format
@@ -140,7 +139,6 @@ def getPlotsDefList( flags ):
 
         # flatten json histo dict
         plotDictFlat = flatten_json( newPlotDict )
-        print( "\t - Flattened-json plot definition : ", plotDictFlat )
 
         # Turn json into string
         plotDefStr = str( json.dumps( plotDictFlat ) )
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/python/InDetTrackPerfMonConfig.py b/InnerDetector/InDetValidation/InDetTrackPerfMon/python/InDetTrackPerfMonConfig.py
index 1883c4e9676c8aef3d2576b9a9eac418ba9fef8c..16217b0749c39cc87594cb55a0a0e8cf6ee5df05 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/python/InDetTrackPerfMonConfig.py
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/python/InDetTrackPerfMonConfig.py
@@ -13,6 +13,57 @@ from AthenaConfiguration.ComponentFactory import CompFactory
 from AthenaCommon.Logging import logging
 
 
+def JsonPlotsDefReadToolCfg( flags, name="JsonPlotsDefReadTool", **kwargs ):
+    '''
+    Tool to read the plots definitions from an input file in JSON format
+    '''
+    log = logging.getLogger( "JsonPlotsDefReadTool" )
+    acc = ComponentAccumulator()
+
+    ## Getting list of strings with plots definitions
+    from InDetTrackPerfMon.ConfigUtils import getPlotsDefList
+    plotsDefList = getPlotsDefList( flags )
+    log.debug( "Loading the following plot definitions:" )
+    for plotDef in plotsDefList : log.debug( "\t-> %s", plotDef )
+
+    kwargs.setdefault( "PlotsDefs", plotsDefList )
+
+    acc.setPrivateTools(
+        CompFactory.IDTPM.JsonPlotsDefReadTool( name, **kwargs ) )
+    return acc
+
+
+def PlotsDefReadToolCfg( flags, name="PlotsDefReadTool", **kwargs ):
+    '''
+    CA-based configuration for the Tool to read the plots definition
+    '''
+    log = logging.getLogger( "PlotsDefReadTool" )
+
+    if flags.PhysVal.IDTPM.plotsDefFormat == "JSON" :
+        return JsonPlotsDefReadToolCfg(
+            flags, name = "JsonPlotsDefReadTool" +
+                flags.PhysVal.IDTPM.currentTrkAna.anaTag, **kwargs )
+
+    log.error( "Non supported plots definition file type %s",
+               flags.PhysVal.IDTPM.plotsDefFormat )
+    return None
+
+
+def PlotsDefinitionSvcCfg( flags, name="PlotsDefSvc", **kwargs ):
+    '''
+    CA-based configuration for the PlotsDefinition Service
+    '''
+    acc = ComponentAccumulator()
+
+    if "PlotsDefReadTool" not in kwargs:
+        kwargs.setdefault( "PlotsDefReadTool", acc.popToolsAndMerge(
+            PlotsDefReadToolCfg( flags ) ) )
+
+    acc.addService(
+        CompFactory.PlotsDefinitionSvc( name, **kwargs ) )
+    return acc
+
+
 def TrackAnalysisDefinitionSvcCfg( flags, name="TrkAnaDefSvc", **kwargs ):
     '''
     CA-based configuration for the TrackAnalysisDefinition Service
@@ -59,9 +110,15 @@ def InDetTrackPerfMonToolCfg( flags, name="InDetTrackPerfMonTool", **kwargs ):
 
     kwargs.setdefault( "AnaTag", flags.PhysVal.IDTPM.currentTrkAna.anaTag )
 
+    ## TrackAnalysisDefinitionSvc
     acc.merge( TrackAnalysisDefinitionSvcCfg( flags,
                    name="TrkAnaDefSvc"+flags.PhysVal.IDTPM.currentTrkAna.anaTag ) )
 
+    ## PlotsDefinitionSvc
+    acc.merge( PlotsDefinitionSvcCfg( flags,
+                    name="PlotsDefSvc"+flags.PhysVal.IDTPM.currentTrkAna.anaTag ) )
+
+    ## now the sub-tools
     if "TrackQualitySelectionTool" not in kwargs:
         from InDetTrackPerfMon.InDetSelectionConfig import TrackQualitySelectionToolCfg
         kwargs.setdefault( "TrackQualitySelectionTool", acc.popToolsAndMerge(
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/scripts/runIDTPM.py b/InnerDetector/InDetValidation/InDetTrackPerfMon/scripts/runIDTPM.py
index b6b7b908f3ca8c45d18daae29a1a23d975a0985f..8b47e7780b1d5cc7555cc3248c6fb2e57c2c8839 100755
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/scripts/runIDTPM.py
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/scripts/runIDTPM.py
@@ -15,8 +15,8 @@ def GetCustomAthArgs() :
     IDTPMparser.add_argument( "--trkAnaCfgFile", help='File with track analysis setup (.json format)', default='Default' )
     IDTPMparser.add_argument( "--unpackTrigChains", help="Run each configured trigger chain in a separate track analysis", action="store_true", default=False )
     IDTPMparser.add_argument( "--plotsDefFormat", help='Format of the plots definition file', default="JSON" )
-    IDTPMparser.add_argument( "--plotsDefFileList", help='Plain txt file containing the list of .json file names with the plots definitions', default="InDetTrackPerfMon/plotsDefFileList_default.txt" )
-    IDTPMparser.add_argument( "--plotsCommonValuesFile", help='JSON file listing all the default values to be used in plots', default="InDetTrackPerfMon/IDTPMPlotCommonValues.json" )
+    IDTPMparser.add_argument( "--plotsDefFileList", help='Plain txt file containing the list of .json file names with the plots definitions', default="InDetTrackPerfMon/PlotsDefFileList_default.txt" )
+    IDTPMparser.add_argument( "--plotsCommonValuesFile", help='JSON file listing all the default values to be used in plots', default="InDetTrackPerfMon/PlotsDefCommonValues.json" )
     IDTPMparser.add_argument( "--sortPlotsByChain", help="Arrange plots first in subdirectories named after the current chain", action="store_true", default=False )
     return IDTPMparser.parse_args()
 
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/InDetTrackPerfMon/IPlotsDefReadTool.h b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/IPlotsDefReadTool.h
similarity index 100%
rename from InnerDetector/InDetValidation/InDetTrackPerfMon/InDetTrackPerfMon/IPlotsDefReadTool.h
rename to InnerDetector/InDetValidation/InDetTrackPerfMon/src/IPlotsDefReadTool.h
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/InDetTrackPerfMonTool.cxx b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/InDetTrackPerfMonTool.cxx
index e4e8afb819758292120e80a3e49e8e5515774236..f8bcdabb9c3d3ab531692f77f3f1540783b13765 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/InDetTrackPerfMonTool.cxx
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/InDetTrackPerfMonTool.cxx
@@ -74,6 +74,23 @@ StatusCode InDetTrackPerfMonTool::initialize() {
   ATH_CHECK( m_truthParticleName.initialize( 
       m_trkAnaDefSvc->useTruth() and not m_truthParticleName.key().empty() ) );
 
+  /// Retrieving list of configured chains
+  const std::vector< std::string >& configuredChains = m_trkAnaDefSvc->configuredChains();
+  m_trkAnaPlotsMgrVec.reserve( configuredChains.size() );
+
+  /// booking analyses
+  for( const std::string& thisChain : configuredChains ) {
+    ATH_MSG_DEBUG( "Booking TrkAnalysis/histograms for chain : " << thisChain );
+
+    /// Instantiating a different TrkAnalysis object (with corresponding histograms) 
+    /// for every configured chain
+    m_trkAnaPlotsMgrVec.emplace_back(
+        std::make_unique< IDTPM::TrackAnalysisPlotsMgr >(
+            m_trkAnaDefSvc->plotsFullDir( thisChain ),
+            m_anaTag.value(),
+            thisChain ) );
+  } // close m_configuredChains loop 
+
   return StatusCode::SUCCESS;
 }
 
@@ -85,6 +102,26 @@ StatusCode InDetTrackPerfMonTool::bookHistograms()
 {
   ATH_MSG_INFO( "Booking plots" );
 
+  for( size_t iAna=0 ; iAna < m_trkAnaPlotsMgrVec.size() ; iAna++ ) {
+
+    /// initialising/booking histograms
+    ATH_CHECK( m_trkAnaPlotsMgrVec[iAna]->initialize() );
+
+    /// Register booked histogram to corresponding monitoring group
+    /// Register "plain" histograms (including TH1/2/3 and TProfiles)
+    std::vector< HistData > hists = m_trkAnaPlotsMgrVec[iAna]->retrieveBookedHistograms();
+    for ( size_t ih=0 ; ih<hists.size() ; ih++ ) {
+      ATH_CHECK( regHist( hists[ih].first, hists[ih].second, all ) );
+    }
+
+    // do the same for Efficiencies, but there's a twist:
+    std::vector< EfficiencyData > effs = m_trkAnaPlotsMgrVec[iAna]->retrieveBookedEfficiencies();
+    for ( size_t ie=0 ; ie<effs.size() ; ie++ ) {
+      ATH_CHECK( regEfficiency( effs[ie].first, MonGroup( this, effs[ie].second, all ) ) );
+    }
+
+  } // closing loop over TrkAnalyses
+  
   return StatusCode::SUCCESS;
 }
 
@@ -106,7 +143,6 @@ StatusCode InDetTrackPerfMonTool::fillHistograms() {
   /// filling TrackAnalysisCollections
   ATH_CHECK( loadCollections( thisTrkAnaCollections ) );
 
-  /// some debug printouts
   ATH_MSG_DEBUG( "Processing event = " << pie->eventNumber() <<
                  "\n==========================================" );
   ATH_MSG_DEBUG( "ALL Track Info: " << thisTrkAnaCollections.printInfo() );
@@ -134,7 +170,9 @@ StatusCode InDetTrackPerfMonTool::fillHistograms() {
   /// -------------------------------------------
   /// one TrkAnalysis per configured chain (trigger only)
   /// only one dummy chain (named "Offline") for offline analysis
-  for( const std::string& thisChain : m_trkAnaDefSvc->configuredChains() ) {
+  for( size_t iAna=0 ; iAna < m_trkAnaPlotsMgrVec.size() ; iAna++ ) {
+
+    const std::string& thisChain = m_trkAnaPlotsMgrVec[iAna]->chain();
     ATH_MSG_DEBUG( "Processing chain = " << thisChain );
 
     /// ----------------------------------
@@ -212,6 +250,7 @@ StatusCode InDetTrackPerfMonTool::fillHistograms() {
       /// --------------------------
       /// --- Filling histograms ---
       /// --------------------------
+      ATH_CHECK( m_trkAnaPlotsMgrVec[iAna]->fill( thisTrkAnaCollections ) );
 
     } // close selectedRois loop
 
@@ -228,6 +267,12 @@ StatusCode InDetTrackPerfMonTool::procHistograms() {
 
   ATH_MSG_INFO( "Finalizing plots" );
 
+  if( endOfRunFlag() ) {
+    for( size_t iAna=0 ; iAna < m_trkAnaPlotsMgrVec.size() ; iAna++ ) {
+      m_trkAnaPlotsMgrVec[iAna]->finalize();
+    }
+  }
+
   ATH_MSG_INFO( "Successfully finalized hists" );
 
   return StatusCode::SUCCESS;
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/InDetTrackPerfMonTool.h b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/InDetTrackPerfMonTool.h
index bc379903448ee1193d82e7ea70ac395e1761455b..cd29603c17c07fd33a7cb950e7161d5277187853 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/InDetTrackPerfMonTool.h
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/InDetTrackPerfMonTool.h
@@ -20,8 +20,6 @@
 /// Athena includes
 #include "AthenaMonitoring/ManagedMonitorToolBase.h"
 #include "TrigDecisionTool/TrigDecisionTool.h"
-/// TODO - To be included in later MRs
-//#include "AsgAnalysisInterfaces/IGoodRunsListSelectionTool.h"
 
 /// local includes
 #include "InDetTrackPerfMon/ITrackAnalysisDefinitionSvc.h"
@@ -29,8 +27,7 @@
 #include "RoiSelectionTool.h"
 #include "InDetTrackPerfMon/ITrackSelectionTool.h"
 #include "ITrackMatchingTool.h"
-/// TODO - To be included in later MRs
-//#include "TrackAnalysisPlotsMgr.h"
+#include "TrackAnalysisPlotsMgr.h"
 
 /// STL includes
 #include <string>
@@ -72,25 +69,10 @@ private :
     SG::ReadHandleKey<xAOD::TruthParticleContainer> m_truthParticleName {
         this, "TruthParticleContainerName",  "TruthParticles", "Name of container of TruthParticles" };
 
-    /// Offline Primary vertex container's name
-    //SG::ReadHandleKey<xAOD::VertexContainer> m_offlineVertexContainerName {
-    //    this, "VertexContainerName", "PrimaryVertices", "offline vertices" };
-
-    /// Truth vertex container's name
-    //SG::ReadHandleKey<xAOD::TruthVertexContainer> m_truthVertexContainerName {
-    //    this, "TruthVertexContainerName",  "TruthVertices", "truth vertices" };
-
     /// EventInfo container name
     SG::ReadHandleKey<xAOD::EventInfo> m_eventInfoContainerName {
         this, "EventInfoContainerName", "EventInfo", "event info" };
 
-    /// TODO - To be included in later MRs
-    //SG::ReadHandleKey<xAOD::TruthEventContainer> m_truthEventName {
-    //    this, "TruthEvents", "TruthEvents", "Name of the truth events container probably either TruthEvent or TruthEvents" };
-
-    //SG::ReadHandleKey<xAOD::TruthPileupEventContainer> m_truthPileUpEventName {
-    //    this, "TruthPileupEvents", "TruthPileupEvents", "Name of the truth pileup events container probably TruthPileupEvent(s)" };
-
     PublicToolHandle< Trig::TrigDecisionTool > m_trigDecTool {
         this, "TrigDecisionTool", "Trig::TrigDecisionTool/TrigDecisionTool", "" };
 
@@ -113,9 +95,8 @@ private :
     /// TrackAnalysisDefinitionSvc
     ITrackAnalysisDefinitionSvc* m_trkAnaDefSvc;
 
-    /// TODO - To be included in later MRs
     /// plots
-    //std::vector< std::unique_ptr< IDTPM::TrackAnalysisPlotsMgr > >  m_trkAnaPlotsMgrVec;
+    std::vector< std::unique_ptr< IDTPM::TrackAnalysisPlotsMgr > >  m_trkAnaPlotsMgrVec;
 };
 
 #endif
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/JsonPlotsDefReadTool.h b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/JsonPlotsDefReadTool.h
index b79c5db6bdc3b929af8616135f95a1fe4609b2bb..09e2516ad782272a5364510df18eedad74efe2e5 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/JsonPlotsDefReadTool.h
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/JsonPlotsDefReadTool.h
@@ -16,7 +16,7 @@
 #include "AsgTools/AsgTool.h"
 
 /// Local includes
-#include "InDetTrackPerfMon/IPlotsDefReadTool.h"
+#include "IPlotsDefReadTool.h"
 
 
 namespace IDTPM {
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotMgr.cxx b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotMgr.cxx
index 6aeaadc6a2713e8bec7aa607de58daee66f106d5..387a9d4ddf3ad480eff37d5c75b721f9e3cc9153 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotMgr.cxx
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotMgr.cxx
@@ -9,6 +9,7 @@
 
 /// local include(s)
 #include "PlotMgr.h"
+#include "InDetTrackPerfMon/IPlotsDefinitionSvc.h"
 
 /// Gaudi include(s)
 #include "GaudiKernel/ISvcLocator.h"
@@ -27,8 +28,7 @@ IDTPM::PlotMgr::PlotMgr(
     PlotMgr* pParent ) :
         PlotBase( pParent, dirName ),
         AthMessaging( "PlotMgr"+anaTag ),
-        m_anaTag( anaTag ),
-        m_plotsDefSvc( nullptr ) { }
+        m_anaTag( anaTag ) { }
 
 
 /// ------------------
@@ -38,13 +38,6 @@ StatusCode IDTPM::PlotMgr::initialize()
 {
   /// intialize PlotBase
   PlotBase::initialize();
-
-  /// load plotDefSvc 
-  if( not m_plotsDefSvc ) {
-    ISvcLocator* svcLoc = Gaudi::svcLocator();
-    ATH_CHECK( svcLoc->service( "PlotsDefSvc"+m_anaTag, m_plotsDefSvc ) );
-  }
-
   return StatusCode::SUCCESS;
 }
 
@@ -57,11 +50,21 @@ IDTPM::SinglePlotDefinition IDTPM::PlotMgr::retrieveDefinition(
     const std::string& folderOverride, 
     const std::string& nameOverride ) const
 {
-  /// Retrieve copy of SinglePlotDefinition
-  SinglePlotDefinition sDef = m_plotsDefSvc->definition( identifier );
+  /// Loading PlotsDefinitionSvc
+  IPlotsDefinitionSvc* plotsDefSvc;
+  ISvcLocator* svcLoc = Gaudi::svcLocator();
+  StatusCode sc = svcLoc->service( "PlotsDefSvc"+m_anaTag, plotsDefSvc );
+  if( sc.isFailure() ) {
+    ATH_MSG_ERROR( "Could not load PlotsDefSvc"+m_anaTag );
+    SinglePlotDefinition nullDef;
+    return nullDef;
+  }
+
+  /// retrieve a copy of the plot definition
+  SinglePlotDefinition sDef = plotsDefSvc->definition( identifier );
 
   /// Check if definition is empty or non-valid 
-  if( sDef.isEmpty() or !sDef.isValid() )  return sDef;
+  if( sDef.isEmpty() or not sDef.isValid() )  return sDef;
 
   /// Override directory?
   if( not folderOverride.empty() )  sDef.folder( folderOverride );
@@ -87,6 +90,7 @@ StatusCode IDTPM::PlotMgr::book(
   pHisto = Book1D( def.name(), def.titleDigest(),
                    def.nBinsX(), def.xLow(), def.xHigh(),
                    false );
+
   return StatusCode::SUCCESS;
 }
 
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotMgr.h b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotMgr.h
index e372a1ef76e426f6a831d341c1f3aafc7fce2fdc..e33e3f5a025ee0fdb8a161b96ea437dbe310aa74 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotMgr.h
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotMgr.h
@@ -21,7 +21,6 @@
 #include "AthenaBaseComps/AthMessaging.h"
 
 /// local include(s)
-#include "InDetTrackPerfMon/IPlotsDefinitionSvc.h"
 #include "SinglePlotDefinition.h"
 
 /// STL include(s)
@@ -61,13 +60,13 @@ namespace IDTPM {
     /// @param nameOverride: Allows to override the histo name 
     /// @param folderOverride: Allows to override the folder of the histo
     template < class P >
-    StatusCode book(
+    StatusCode retrieveAndBook(
         P*& pHisto,
         const std::string& identifier,
         const std::string& folderOverride = "",
-        const std::string& nameOverride = "" ) const
+        const std::string& nameOverride = "" )
     {
-      SinglePlotDefinition def =
+      const SinglePlotDefinition& def =
           retrieveDefinition( identifier, folderOverride, nameOverride );
       if( def.isEmpty() or not def.isValid() ) {
         ATH_MSG_WARNING( "Trying to book empty or non-valid plot : " << identifier );
@@ -132,10 +131,6 @@ namespace IDTPM {
 
     std::string m_anaTag;
 
-  private:
-
-    IPlotsDefinitionSvc* m_plotsDefSvc;
-
   }; // class PlotMgr
 
 } // namespace IDTPM
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotsDefinitionSvc.cxx b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotsDefinitionSvc.cxx
index 8e8e1bb40901fc7ccc64b31a3a5051c96a41cb66..6b493fbd103bd53603a8d4f6859233e7c6b29d2a 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotsDefinitionSvc.cxx
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotsDefinitionSvc.cxx
@@ -15,7 +15,7 @@
 /// -------------------
 /// --- Constructor ---
 /// -------------------
-IDTPM::PlotsDefinitionSvc::PlotsDefinitionSvc(
+PlotsDefinitionSvc::PlotsDefinitionSvc(
     const std::string& name, ISvcLocator* pSvcLocator ) :
         AsgService( name, pSvcLocator ),
         m_plotsDefMap{}, m_nullDef()
@@ -27,14 +27,14 @@ IDTPM::PlotsDefinitionSvc::PlotsDefinitionSvc(
 /// ------------------
 /// --- initialize ---
 /// ------------------
-StatusCode IDTPM::PlotsDefinitionSvc::initialize() {
+StatusCode PlotsDefinitionSvc::initialize() {
 
   ATH_MSG_DEBUG( "Initialising " << name() );
 
   ATH_CHECK( m_plotsDefReadTool.retrieve() );
 
   /// Updating plots definition map
-  for( const SinglePlotDefinition& plotDef :
+  for( const IDTPM::SinglePlotDefinition& plotDef :
           m_plotsDefReadTool->getPlotsDefinitions() ) {
     ATH_CHECK( update( plotDef ) );
   }
@@ -62,7 +62,7 @@ StatusCode IDTPM::PlotsDefinitionSvc::initialize() {
 /// ----------------
 /// --- finalize ---
 /// ----------------
-StatusCode IDTPM::PlotsDefinitionSvc::finalize() {
+StatusCode PlotsDefinitionSvc::finalize() {
   ATH_MSG_DEBUG( "Finalized " << name() );
   return StatusCode::SUCCESS;
 }
@@ -71,7 +71,7 @@ StatusCode IDTPM::PlotsDefinitionSvc::finalize() {
 /// ------------------
 /// --- definition ---
 /// ------------------
-const IDTPM::SinglePlotDefinition& IDTPM::PlotsDefinitionSvc::definition(
+const IDTPM::SinglePlotDefinition& PlotsDefinitionSvc::definition(
     const std::string& identifier ) const
 {
   plotsDefMap_t::const_iterator map_it = m_plotsDefMap.find( identifier );
@@ -83,7 +83,7 @@ const IDTPM::SinglePlotDefinition& IDTPM::PlotsDefinitionSvc::definition(
 /// ------------------
 /// ----- update -----
 /// ------------------
-StatusCode IDTPM::PlotsDefinitionSvc::update(
+StatusCode PlotsDefinitionSvc::update(
     const IDTPM::SinglePlotDefinition& def )
 {
   ATH_MSG_DEBUG( "Adding new plot definition: " << def.identifier() );
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotsDefinitionSvc.h b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotsDefinitionSvc.h
index a797f80ded38613cb79500e8be8ea2858d5886b3..df71e4f07b3c958333c467e827024bbff68c53c5 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotsDefinitionSvc.h
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/PlotsDefinitionSvc.h
@@ -22,50 +22,46 @@
 
 /// Local include(s)
 #include "InDetTrackPerfMon/IPlotsDefinitionSvc.h"
-#include "InDetTrackPerfMon/IPlotsDefReadTool.h"
+#include "IPlotsDefReadTool.h"
 #include "SinglePlotDefinition.h"
 
 
-namespace IDTPM {
+class PlotsDefinitionSvc :
+    public asg::AsgService,
+    virtual public IPlotsDefinitionSvc {
 
-  class PlotsDefinitionSvc :
-      public asg::AsgService,
-      virtual public IPlotsDefinitionSvc {
+public:
 
-  public:
+  /// Constructor
+  PlotsDefinitionSvc( const std::string& name, ISvcLocator* pSvcLocator );
 
-    /// Constructor
-    PlotsDefinitionSvc( const std::string& name, ISvcLocator* pSvcLocator );
+  /// Destructor
+  virtual ~PlotsDefinitionSvc() = default;
 
-    /// Destructor
-    virtual ~PlotsDefinitionSvc() = default;
+  /// initialize
+  virtual StatusCode initialize() override;
 
-    /// initialize
-    virtual StatusCode initialize() override;
+  /// finalize
+  virtual StatusCode finalize() override;
 
-    /// finalize
-    virtual StatusCode finalize() override;
+  /// Get the plot definition
+  virtual const IDTPM::SinglePlotDefinition& definition(
+      const std::string& identifier ) const override;
 
-    /// Get the plot definition
-    virtual const SinglePlotDefinition& definition(
-        const std::string& identifier ) const override;
-
-    /// Update the map with a new entry
-    StatusCode update( const SinglePlotDefinition& def );
+  /// Update the map with a new entry
+  StatusCode update( const IDTPM::SinglePlotDefinition& def );
  
-  private:
+private:
 
-    plotsDefMap_t m_plotsDefMap;
+  plotsDefMap_t m_plotsDefMap;
 
-    SinglePlotDefinition m_nullDef;
+  IDTPM::SinglePlotDefinition m_nullDef;
 
-    ToolHandle< IPlotsDefReadTool > m_plotsDefReadTool {
-        this, "PlotsDefReadTool", "IDTPM::InDetTrackPerfMon/IPlotsDefReadTool", "Tool to read plots definitions from parsed list of strings" };
+  ToolHandle< IDTPM::IPlotsDefReadTool > m_plotsDefReadTool {
+      this, "PlotsDefReadTool", "IDTPM::InDetTrackPerfMon/IPlotsDefReadTool", "Tool to read plots definitions from parsed list of strings" };
 
-    std::string m_anaTag;
+  std::string m_anaTag;
   
-  }; // class PlotsDefinitionSvc
-
-} // namespace IDTPM
+}; // class PlotsDefinitionSvc
 
 #endif // > !INDETTRACKPERFMON_PLOTSDEFINITIONSVC_H
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/TrackAnalysisDefinitionSvc.cxx b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/TrackAnalysisDefinitionSvc.cxx
index b96128985269bc5287589a87050a2d934d89d411..17cc6c241529d941164ed38a1d0ca1e9049d873b 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/TrackAnalysisDefinitionSvc.cxx
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/TrackAnalysisDefinitionSvc.cxx
@@ -105,7 +105,6 @@ std::string TrackAnalysisDefinitionSvc::plotsFullDir( std::string chain ) const
     /// add a slash: "subDir" -> "subDir/"
     if( subDir.back() != '/' ) subDir += "/";
   }
-  
 
   return m_sortPlotsByChain.value() ?
          topDir + chain + subDir :
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/TrackAnalysisPlotsMgr.cxx b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/TrackAnalysisPlotsMgr.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..9cb31bb3fd752a329e1f279e544ecd24b3423afd
--- /dev/null
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/TrackAnalysisPlotsMgr.cxx
@@ -0,0 +1,201 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file    TrackAnalysisPlotsMgr.cxx
+ * @author  Marco Aparo <marco.aparo@cern.ch>
+ * @date    19 June 2023
+**/
+
+/// local includes
+#include "TrackAnalysisPlotsMgr.h"
+#include "TrackAnalysisCollections.h"
+#include "ITrackMatchingLookup.h"
+
+/// Gaudi include(s)
+#include "GaudiKernel/ISvcLocator.h"
+#include "GaudiKernel/Service.h"
+
+
+/// -------------------
+/// --- Constructor ---
+/// -------------------
+IDTPM::TrackAnalysisPlotsMgr::TrackAnalysisPlotsMgr(
+    const std::string& dirName,
+    const std::string& anaTag,
+    const std::string& chain,
+    PlotMgr* pParent ) :
+        PlotMgr( dirName, anaTag, pParent ), 
+        m_anaTag( anaTag ), m_chain( chain ),
+        m_directory( dirName ), m_trkAnaDefSvc( nullptr ) { }
+
+
+/// ------------------
+/// --- initialize ---
+/// ------------------
+StatusCode IDTPM::TrackAnalysisPlotsMgr::initialize()
+{
+  ATH_MSG_DEBUG( "Initialising in directory: " << m_directory );
+
+  /// load trkAnaDefSvc 
+  if( not m_trkAnaDefSvc ) {
+    ISvcLocator* svcLoc = Gaudi::svcLocator();
+    ATH_CHECK( svcLoc->service( "TrkAnaDefSvc"+m_anaTag, m_trkAnaDefSvc ) );
+  }
+
+  /// Track parameters plots
+  if( m_trkAnaDefSvc->plotTrackParameters() ) {
+    m_plots_trkParam_vsTest = std::make_unique< TrackParametersPlots >(
+        this, "Tracks/Parameters", m_anaTag, m_trkAnaDefSvc->testTag() );
+    m_plots_trkParam_vsRef = std::make_unique< TrackParametersPlots >(
+        this, "Tracks/Parameters", m_anaTag, m_trkAnaDefSvc->referenceTag() );
+  } 
+
+  /// TODO - To be included in later MRs
+  /// Efficiency plots
+  /*if( m_trkAnaDefSvc->plotEfficiencies() ) {
+    m_plots_eff_vsTest = std::make_unique< InDetPerfPlot_Efficiencies >(
+        this, "Tracks/Efficiencies", m_anaTag, m_trkAnaDefSvc->testTag() );
+    m_plots_eff_vsRef = std::make_unique< InDetPerfPlot_Efficiencies >(
+        this, "Tracks/Efficiencies", m_anaTag, m_trkAnaDefSvc->referenceTag() );
+  }*/
+
+  /// Offline electron plots
+  /*if( m_trkAnaDefSvc->plotOfflineElectrons() ) {
+    m_plots_offEle = std::make_unique< InDetPerfPlot_OfflineElectron >(
+        this, "Tracks/Parameters", m_anaTag );
+    if( m_trkAnaDefSvc->plotEfficiencies() ) {
+      m_plots_eff_vsOffEle = std::make_unique< InDetPerfPlot_OfflineElectron >(
+          this, "Tracks/Efficiencies", m_anaTag, true );
+    }
+  }*/
+
+  /// intialize PlotBase
+  ATH_CHECK( PlotMgr::initialize() );
+
+  return StatusCode::SUCCESS;
+}
+
+
+/// --------------------------
+/// ------ General fill ------
+/// --------------------------
+StatusCode IDTPM::TrackAnalysisPlotsMgr::fill(
+    TrackAnalysisCollections& trkAnaColls, float weight )
+{
+  /// Plots w.r.t. test tracks quantities
+  if( m_trkAnaDefSvc->isTestTruth() ) {
+    ATH_CHECK( fillPlotsTest(
+        trkAnaColls.testTruthVec( TrackAnalysisCollections::InRoI ),
+        trkAnaColls.matches(), weight ) );
+  } else {
+    ATH_CHECK( fillPlotsTest(
+        trkAnaColls.testTrackVec( TrackAnalysisCollections::InRoI ),
+        trkAnaColls.matches(), weight ) );
+  } 
+
+  /// Plots w.r.t. reference tracks quantities
+  if( m_trkAnaDefSvc->isReferenceTruth() ) {
+    ATH_CHECK( fillPlotsReference(
+        trkAnaColls.refTruthVec( TrackAnalysisCollections::InRoI ),
+        trkAnaColls.matches(), weight ) );
+  } else {
+    ATH_CHECK( fillPlotsReference(
+        trkAnaColls.refTrackVec( TrackAnalysisCollections::InRoI ),
+        trkAnaColls.matches(), weight ) );
+  } 
+
+  return StatusCode::SUCCESS;
+}
+
+
+/// ------------------------------
+/// --- Fill plots w.r.t. test ---
+/// ------------------------------
+template< typename PARTICLE >
+StatusCode IDTPM::TrackAnalysisPlotsMgr::fillPlotsTest(
+    const std::vector< const PARTICLE* >& particles,
+    const ITrackMatchingLookup& matches, float weight )
+{
+  for( const PARTICLE* particle : particles ) {
+    /// track parameters plots
+    if( m_plots_trkParam_vsTest ) {
+      ATH_CHECK( m_plots_trkParam_vsTest->fillPlots( *particle, weight ) );
+    }
+
+    bool isMatched = matches.isTestMatched( *particle );
+    if( isMatched ) {
+      ATH_MSG_DEBUG( "Test track is matched to a reference" );
+    }
+
+    /// TODO - To be included in later MRs
+    /// efficiency plots
+    /*if( m_plots_eff_vsTest ) {
+      ATH_CHECK( m_plots_eff_vsTest->fill( *particle, isMatched, weight ) );
+    }*/
+
+  } // close loop over particles
+
+  return StatusCode::SUCCESS;
+}
+
+template StatusCode
+IDTPM::TrackAnalysisPlotsMgr::fillPlotsTest< xAOD::TrackParticle >(
+    const std::vector< const xAOD::TrackParticle* >& particles,
+    const ITrackMatchingLookup& matches, float weight );
+
+template StatusCode
+IDTPM::TrackAnalysisPlotsMgr::fillPlotsTest< xAOD::TruthParticle >(
+    const std::vector< const xAOD::TruthParticle* >& particles,
+    const ITrackMatchingLookup& matches, float weight );
+
+
+/// -----------------------------------
+/// --- Fill plots w.r.t. reference ---
+/// -----------------------------------
+template< typename PARTICLE >
+StatusCode IDTPM::TrackAnalysisPlotsMgr::fillPlotsReference(
+    const std::vector< const PARTICLE* >& particles,
+    const ITrackMatchingLookup& matches, float weight )
+{
+  for( const PARTICLE* particle : particles ) {
+    /// track parameters plots
+    if( m_plots_trkParam_vsRef ) {
+      ATH_CHECK( m_plots_trkParam_vsRef->fillPlots( *particle, weight ) );
+    }
+
+    bool isMatched = matches.isRefMatched( *particle );
+    if( isMatched ) {
+      ATH_MSG_DEBUG( "Reference track is matched to (at least) a test" );
+    }
+
+    /// TODO - To be included in later MRs
+    /// efficiency plots
+    /*if( m_plots_eff_vsRef ) {
+      ATH_CHECK( m_plots_eff_vsRef->fill( *particle, isMatched, weight ) );
+    }*/
+
+    /// TODO - To be included in later MRs
+    /// offline electron plots
+    /*if( m_plots_offEle ) {
+      ATH_CHECK( m_plots_offEle->fill( *particle, false, weight ) );
+    }
+    if( m_plots_eff_vsOffEle ) {
+      ATH_CHECK( m_plots_eff_vsOffEle->fill( *particle, isMatched, weight ) );
+    }*/
+
+  } // close loop over particles
+
+  return StatusCode::SUCCESS;
+}
+
+template StatusCode
+IDTPM::TrackAnalysisPlotsMgr::fillPlotsReference< xAOD::TrackParticle >(
+    const std::vector< const xAOD::TrackParticle* >& particles,
+    const ITrackMatchingLookup& matches, float weight );
+
+template StatusCode
+IDTPM::TrackAnalysisPlotsMgr::fillPlotsReference< xAOD::TruthParticle >(
+    const std::vector< const xAOD::TruthParticle* >& particles,
+    const ITrackMatchingLookup& matches, float weight );
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/TrackAnalysisPlotsMgr.h b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/TrackAnalysisPlotsMgr.h
new file mode 100644
index 0000000000000000000000000000000000000000..89e8f0cc44957dff06f07627b6b8735b4676892e
--- /dev/null
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/TrackAnalysisPlotsMgr.h
@@ -0,0 +1,103 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef INDETTRACKPERFMON_TRACKANALYSISPLOTSMGR_H
+#define INDETTRACKPERFMON_TRACKANALYSISPLOTSMGR_H
+
+/**
+ * @file    TrackAnalysisPlotsMgr.h
+ * @brief   class to manage (book, fill) all the plots for the
+ *          processed TrackAnalysis for tracking performance validation
+ * @author  Marco Aparo <marco.aparo@cern.ch>
+ * @date    19 June 2023
+**/
+
+/// xAOD includes
+#include "xAODTracking/TrackParticle.h"
+#include "xAODTruth/TruthParticle.h"
+
+/// local includes
+#include "InDetTrackPerfMon/ITrackAnalysisDefinitionSvc.h"
+#include "PlotMgr.h"
+#include "plots/TrackParametersPlots.h"
+/// TODO - to be included in later MRs
+//#include "InDetTrackPerfMon/InDetPerfPlot_Efficiencies.h"
+//#include "InDetTrackPerfMon/InDetPerfPlot_OfflineElectron.h"
+
+/// STD includes
+#include <string>
+#include <memory>
+#include <vector>
+
+
+namespace IDTPM {
+
+  /// Forward-declaring internal classes
+  class TrackAnalysisCollections;
+  class ITrackMatchingLookup;
+
+  class TrackAnalysisPlotsMgr : public PlotMgr {
+
+  public :
+
+    /// Constructor
+    TrackAnalysisPlotsMgr( const std::string& dirName,
+                           const std::string& anaTag,
+                           const std::string& chain,
+                           PlotMgr* pParent = nullptr );
+
+    /// Destructor
+    virtual ~TrackAnalysisPlotsMgr() = default;
+
+    /// initialize
+    StatusCode initialize();
+
+    /// return members
+    const std::string& anaTag() const { return m_anaTag; }
+    const std::string& chain() const { return m_chain; }
+    const std::string& directory() const { return m_directory; }
+
+    /// General fill method
+    StatusCode fill( TrackAnalysisCollections& trkAnaColls, float weight=1.0 );
+
+    /// Fill all plots w.r.t. test tracks quantities for a specific
+    /// collection (trigger tracks, offline tracks, truth particles)
+    template< typename PARTICLE > 
+    StatusCode fillPlotsTest(
+        const std::vector< const PARTICLE* >& particles,
+        const ITrackMatchingLookup& matches, float weight=1.0 );
+
+    /// Fill all plots w.r.t. reference tracks quantities for a specific
+    /// collection (trigger tracks, offline tracks, truth particles)
+    template< typename PARTICLE > 
+    StatusCode fillPlotsReference(
+        const std::vector< const PARTICLE* >& particles,
+        const ITrackMatchingLookup& matches, float weight=1.0 );
+
+  private :
+
+    std::string m_anaTag;
+    std::string m_chain;
+    std::string m_directory;
+
+    /// TrackAnalysis definition service to "hold" the histograms configurations/flags
+    ITrackAnalysisDefinitionSvc* m_trkAnaDefSvc;
+
+    /// TODO - to be included in later MRs
+    /// Plot categories
+    /// plots w.r.t. test tracks parameters
+    std::unique_ptr< TrackParametersPlots >  m_plots_trkParam_vsTest;
+    //std::unique_ptr< InDetPerfPlot_Efficiencies >     m_plots_eff_vsTest;
+    /// plots w.r.t. reference tracks parameters
+    std::unique_ptr< TrackParametersPlots >  m_plots_trkParam_vsRef;
+    //std::unique_ptr< InDetPerfPlot_Efficiencies >     m_plots_eff_vsRef;
+    /// plots w.r.t. reference offline electron
+    //std::unique_ptr< InDetPerfPlot_OfflineElectron >  m_plots_offEle;
+    //std::unique_ptr< InDetPerfPlot_OfflineElectron >  m_plots_eff_vsOffEle;
+
+  }; // class TrackAnalysisPlotsMgr
+
+} // namespace IDTPM
+
+#endif // > !INDETTRACKPERFMON_TRACKANALYSISPLOTSMGR_H
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/components/InDetTrackPerfMon_entries.cxx b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/components/InDetTrackPerfMon_entries.cxx
index 4f8e68ddf19141cf8f8a34c222c7b2b29b31666b..e7e9f2bd6af56d643dcbe39cbdafea44a1a5ad11 100644
--- a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/components/InDetTrackPerfMon_entries.cxx
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/components/InDetTrackPerfMon_entries.cxx
@@ -15,12 +15,13 @@
 #include "../TrackTruthMatchingTool.h"
 #include "../TruthTrackMatchingTool.h"
 #include "../DeltaRMatchingTool.h"
-/// TODO - To be included in later MRs
-//#include "../PlotsDefinitionSvc.h"
-//#include "../JsonPlotsDefReadTool.h"
+#include "../PlotsDefinitionSvc.h"
+#include "../JsonPlotsDefReadTool.h"
 
 DECLARE_COMPONENT( InDetTrackPerfMonTool )
 DECLARE_COMPONENT( TrackAnalysisDefinitionSvc )
+DECLARE_COMPONENT( PlotsDefinitionSvc )
+DECLARE_COMPONENT( IDTPM::JsonPlotsDefReadTool )
 DECLARE_COMPONENT( IDTPM::TrackQualitySelectionTool )
 DECLARE_COMPONENT( IDTPM::RoiSelectionTool )
 DECLARE_COMPONENT( IDTPM::TrackRoiSelectionTool )
@@ -34,6 +35,3 @@ DECLARE_COMPONENT( IDTPM::TruthTrackMatchingTool )
 DECLARE_COMPONENT( IDTPM::DeltaRMatchingTool_trk )
 DECLARE_COMPONENT( IDTPM::DeltaRMatchingTool_trkTruth )
 DECLARE_COMPONENT( IDTPM::DeltaRMatchingTool_truthTrk )
-/// TODO - To be included in later MRs
-//DECLARE_COMPONENT( IDTPM::PlotsDefinitionSvc )
-//DECLARE_COMPONENT( IDTPM::JsonPlotsDefReadTool )
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/plots/README.md b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/plots/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..c412f3000923f3d249494a3c6dc524b55db16e3c
--- /dev/null
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/plots/README.md
@@ -0,0 +1,6 @@
+# Plots categories
+
+This directory holds dedicated classes for each plot category in this package.
+Currently available categories are:
+
+- `TrackParametersPlots`: for plots regarding the basic track parameters (pT, eta, etc.). They are saved in the "Tracks/Parameters" sub-directory of the output HIST file.
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/plots/TrackParametersPlots.cxx b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/plots/TrackParametersPlots.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..8902662abd8e919492ab05775565f7feeb4bd72c
--- /dev/null
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/plots/TrackParametersPlots.cxx
@@ -0,0 +1,80 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file    TrackParametersPlots.cxx
+ * @author  Marco Aparo <marco.aparo@cern.ch> 
+ **/
+
+/// local include(s)
+#include "TrackParametersPlots.h"
+#include "../TrackParmetersHelper.h"
+
+
+/// -----------------------
+/// ----- Constructor -----
+/// -----------------------
+IDTPM::TrackParametersPlots::TrackParametersPlots(
+    PlotMgr* pParent, const std::string& dirName, 
+    const std::string& anaTag, const std::string& trackType ) :
+        PlotMgr( dirName, anaTag, pParent ), 
+        m_trackType( trackType ) { }
+
+
+/// ---------------------------
+/// --- Book the histograms ---
+/// ---------------------------
+void IDTPM::TrackParametersPlots::initializePlots()
+{
+  StatusCode sc = bookPlots();
+  if( sc.isFailure() ) {
+    ATH_MSG_ERROR( "Failed to book track parameters plots" );
+  }
+}
+
+
+StatusCode IDTPM::TrackParametersPlots::bookPlots()
+{
+  ATH_MSG_DEBUG( "Booking track parameters plots in " << getDirectory() ); 
+
+  ATH_CHECK( retrieveAndBook( m_pt,   m_trackType+"_pt" ) );
+  ATH_CHECK( retrieveAndBook( m_eta,  m_trackType+"_eta" ) );
+
+  return StatusCode::SUCCESS;
+}
+
+
+/// -----------------------------
+/// --- Dedicated fill method ---
+/// -----------------------------
+template< typename PARTICLE >
+StatusCode IDTPM::TrackParametersPlots::fillPlots(
+    const PARTICLE& particle, float weight )
+{
+  /// Compute track parameters - TODO: add more...
+  float ppt    = pT( particle ) / Gaudi::Units::GeV;
+  float peta   = eta( particle );
+
+  /// Fill the histograms
+  ATH_CHECK( fill( m_pt,  ppt,   weight ) );
+  ATH_CHECK( fill( m_eta, peta,  weight ) );
+
+  return StatusCode::SUCCESS;
+}
+
+template StatusCode IDTPM::TrackParametersPlots::fillPlots< xAOD::TrackParticle >(
+    const xAOD::TrackParticle&, float weight );
+
+template StatusCode IDTPM::TrackParametersPlots::fillPlots< xAOD::TruthParticle >(
+    const xAOD::TruthParticle&, float weight );
+
+
+/// -------------------------
+/// ----- finalizePlots -----
+/// -------------------------
+void IDTPM::TrackParametersPlots::finalizePlots()
+{
+  ATH_MSG_DEBUG( "Finalising track parameters plots" );
+  /// print stat here if needed
+}
diff --git a/InnerDetector/InDetValidation/InDetTrackPerfMon/src/plots/TrackParametersPlots.h b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/plots/TrackParametersPlots.h
new file mode 100644
index 0000000000000000000000000000000000000000..f5e983349457d0728dad5dd7c7f43bf1b5f3ba9b
--- /dev/null
+++ b/InnerDetector/InDetValidation/InDetTrackPerfMon/src/plots/TrackParametersPlots.h
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef INDETTRACKPERFMON_PLOTS_TRACKPARAMETERSPLOTS_H
+#define INDETTRACKPERFMON_PLOTS_TRACKPARAMETERSPLOTS_H
+
+/**
+ * @file    TrackParametersPlots.h
+ * @author  Marco Aparo <marco.aparo@cern.ch> 
+ **/
+
+/// local includes
+#include "../PlotMgr.h"
+
+
+namespace IDTPM {
+
+  class TrackParametersPlots : public PlotMgr {
+
+  public:
+
+    /// Constructor
+    TrackParametersPlots(
+        PlotMgr* pParent,
+        const std::string& dirName,
+        const std::string& anaTag,
+        const std::string& trackType );
+
+    /// Destructor
+    virtual ~TrackParametersPlots() = default;
+
+    /// Dedicated fill method (for tracks and/or truth particles)
+    template< typename PARTICLE >
+    StatusCode fillPlots( const PARTICLE& particle, float weight );
+
+    /// Book the histograms
+    void initializePlots(); // needed to override PlotBase
+    StatusCode bookPlots();
+
+    /// Print out final stats on histograms
+    void finalizePlots();
+
+  private:
+
+    std::string m_trackType;
+
+    TH1* m_pt;
+    TH1* m_eta;
+    /// TODO - include more plots
+
+  }; // class TrackParametersPlots
+
+} // namespace IDTPM
+
+#endif // > ! INDETTRACKPERFMON_PLOTS_TRACKPARAMETERSPLOTS_H