diff --git a/core/qa/CbmQaIO.cxx b/core/qa/CbmQaIO.cxx
index f414c3f2b802755e8ca7fd48b0a9753b5668e191..e09b028a0a256f886a1f73ff399c6437f5ecc3d2 100644
--- a/core/qa/CbmQaIO.cxx
+++ b/core/qa/CbmQaIO.cxx
@@ -9,30 +9,21 @@
 
 #include "CbmQaIO.h"
 
+#include "TFile.h"
+
 // ---------------------------------------------------------------------------------------------------------------------
 //
-CbmQaIO::CbmQaIO(const char* folderName, const char* prefixName, TFolder* pParentFolder)
-  : fsRootFolderName(folderName)
-  , fsPrefix(prefixName)
-  , fpParentFolder(pParentFolder)
+CbmQaIO::CbmQaIO(const char* prefixName, std::shared_ptr<ObjList_t> pObjList)
+  : fsPrefix(prefixName)
+  , fpvObjList(pObjList)
 {
-  if (fpParentFolder) { fpFolderRoot = fpParentFolder->AddFolder(fsRootFolderName, fsRootFolderName); }
-  else {
-    fpFolderRoot =
-      new TFolder(fsRootFolderName, fsRootFolderName);  // The name of the folder follows the name of the task
-    fpFolderRoot->SetOwner(true);                       // When true, TFolder owns all added objects
-  }
+  if (!fpvObjList.get()) { fpvObjList = std::make_shared<ObjList_t>(); }
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
 CbmQaIO::~CbmQaIO()
 {
-  // Free memory for fpFolderRoot
-  if (fpFolderRoot && !fpParentFolder) {
-    delete fpFolderRoot;
-    fpFolderRoot = nullptr;
-  }
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -42,3 +33,16 @@ void CbmQaIO::SetHistoProperties(TH1* pHist)
   pHist->SetStats(true);
   pHist->Sumw2();
 }
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void CbmQaIO::WriteToFile(TFile* pOutFile) const
+{
+  LOG(info) << "CbmQaIO: Writing objects in file \033[1;31m" << pOutFile->GetName() << "\033[0m";
+  pOutFile->cd();
+  for (const auto& [pObject, sPath] : (*fpvObjList)) {
+    if (!pOutFile->GetDirectory(sPath)) { pOutFile->mkdir(sPath); }
+    pOutFile->cd(sPath);
+    pObject->Write();
+  }
+}
diff --git a/core/qa/CbmQaIO.h b/core/qa/CbmQaIO.h
index 424ca1c3ffd870f9bc0da71fe985d37d0192fc9f..f2f235b2b38e32f55910018db3b7fb79849c7a68 100644
--- a/core/qa/CbmQaIO.h
+++ b/core/qa/CbmQaIO.h
@@ -16,10 +16,10 @@
 
 #include "TCanvas.h"
 #include "TEfficiency.h"
-#include "TFolder.h"
 #include "TH1.h"
 #include "TH2.h"
 #include "TH3.h"
+#include "TObject.h"
 #include "TParameter.h"
 #include "TProfile.h"
 #include "TProfile2D.h"
@@ -27,11 +27,17 @@
 #include "TROOT.h"
 #include "TString.h"
 
+#include <vector>
+
+class TFile;
+
 /// @brief  ROOT object IO interface for QA
 ///
 /// The class provides interface to write ROOT object into resulted files
 class CbmQaIO {
 public:
+  using ObjList_t = std::vector<std::pair<TObject*, TString>>;
+
   enum class EStoringMode
   {
     kSAMEDIR,  ///< Objects will be stored to root directory
@@ -39,10 +45,9 @@ public:
   };
 
   /// @brief Constructor
-  /// @param folderName    Name of the root folder
   /// @param prefixName    Name of the unique prefix
   /// @param pParentFolder Pointer to parent folder
-  CbmQaIO(const char* folderName, const char* prefixName, TFolder* pParentFolder = nullptr);
+  CbmQaIO(const char* prefixName, std::shared_ptr<ObjList_t> pObjList = nullptr);
 
   /// @brief Destructor
   virtual ~CbmQaIO();
@@ -86,21 +91,30 @@ public:
   template<typename... Args>
   CbmQaTable* MakeTable(const char* name, Args... args);
 
+  /// @brief Creates a ROOT object
+  /// @param name    Name of the object
+  /// @param args... Arguments passed to the object constructor
+  template<typename T, typename... Args>
+  T* MakeObject(const char* name, Args... args);
+
+  /// @brief Sets a common root path to the objects in the output file
+  /// @param path  A path to the object
+  void SetRootFolderName(const char* path) { fsRootFolderName = path; }
+
 protected:
   /// @brief Applies properties on the histogram created with MakeHisto funciton
   /// @param pHist  Pointer to histogram
   virtual void SetHistoProperties(TH1* /*pHits*/);
 
+  /// @brief Writes objects into file
+  /// @param pOutFile Pointer to output ROOT file
+  void WriteToFile(TFile* pOutFile) const;
+
   TString fsRootFolderName = "";  ///< Name of root folder
   TString fsPrefix         = "";  ///< Unique prefix for all writeable root
 
-  EStoringMode fStoringMode = EStoringMode::kSUBDIR;  ///< Objects storing mode
-  TFolder* fpFolderRoot     = nullptr;                ///< Root folder to store histograms and canvases
-  TFolder* fpFolderHist     = nullptr;                ///< Folder for raw histograms
-  TFolder* fpFolderCanv     = nullptr;                ///< Folder for canvases
-  TFolder* fpFolderEff      = nullptr;                ///< Folder for efficiencies
-  TFolder* fpFolderTable    = nullptr;                ///< Folder for tables
-  TFolder* fpParentFolder   = nullptr;                ///< Pointer to parent folder
+  EStoringMode fStoringMode             = EStoringMode::kSUBDIR;  ///< Objects storing mode
+  std::shared_ptr<ObjList_t> fpvObjList = nullptr;                ///< List of registered ROOT objects
 };
 
 
@@ -109,28 +123,8 @@ protected:
 template<typename T, typename... Args>
 T* CbmQaIO::MakeCanvas(const char* nameBase, Args... args)
 {
-  TString name = fsPrefix + "_" + nameBase;
-  if (gROOT->FindObject(name)) {
-    LOG(warn) << fsRootFolderName << ": A previously created canvas \"" << name << "\" will be deleted";
-    T* pCanv = (T*) gROOT->FindObject(name);
-    delete pCanv;
-  }
-
-  // Create a new canvas
-  T* pCanv = new T(name, args...);
-  pCanv->SetLeftMargin(-1.2);
-  pCanv->SetBottomMargin(-1.2);
-
-
-  // Register canvas in the folder
-  if (fStoringMode == EStoringMode::kSUBDIR) {
-    if (!fpFolderCanv) { fpFolderCanv = fpFolderRoot->AddFolder("canvases", "Canvases"); }
-    fpFolderCanv->Add(pCanv);
-  }
-  else if (fStoringMode == EStoringMode::kSAMEDIR) {
-    fpFolderRoot->Add(pCanv);
-  }
-
+  TString sFullName = EStoringMode::kSUBDIR == fStoringMode ? Form("canvases/%s", nameBase) : nameBase;
+  auto* pCanv       = MakeObject<T>(sFullName, args...);
   return pCanv;
 }
 
@@ -139,82 +133,62 @@ T* CbmQaIO::MakeCanvas(const char* nameBase, Args... args)
 template<typename T, typename... Args>
 T* CbmQaIO::MakeEfficiency(const char* nameBase, Args... args)
 {
-  TString name = fsPrefix + "_" + nameBase;
-  if (gROOT->FindObject(name)) {
-    LOG(warn) << fsRootFolderName << ": A previously created histogram \"" << name << "\" will be deleted";
-    auto* pEff = (T*) gROOT->FindObject(name);
-    delete pEff;
-  }
-
-  // Create a new efficiency
-  auto* pEff = new T(name, args...);
-
-  // Register efficiency in the folder
-  if (fStoringMode == EStoringMode::kSUBDIR) {
-    if (!fpFolderEff) { fpFolderEff = fpFolderRoot->AddFolder("efficiencies", "Efficiencies"); }
-    fpFolderEff->Add(pEff);
-  }
-  else if (fStoringMode == EStoringMode::kSAMEDIR) {
-    fpFolderRoot->Add(pEff);
-  }
-
+  TString sFullName = EStoringMode::kSUBDIR == fStoringMode ? Form("efficiencies/%s", nameBase) : nameBase;
+  auto* pEff        = MakeObject<T>(sFullName, args...);
   return pEff;
 }
 
-
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<typename T, typename... Args>
 T* CbmQaIO::MakeHisto(const char* nameBase, Args... args)
 {
-  TString name = fsPrefix + "_" + nameBase;
-  // Check, if the histogram with a given name was already created. If so, delete it
-  if (gROOT->FindObject(name)) {
-    LOG(warn) << fsRootFolderName << ": A previously created histogram \"" << name << "\" will be deleted";
-    T* pHist = (T*) gROOT->FindObject(name);
-    delete pHist;
-  }
-
-  T* pHist = new T(name, args...);
+  TString sFullName = EStoringMode::kSUBDIR == fStoringMode ? Form("histograms/%s", nameBase) : nameBase;
+  auto* pHist       = MakeObject<T>(sFullName, args...);
+  pHist->SetDirectory(0);
   SetHistoProperties(pHist);
-
-  // Register histogram in the folder
-  if (fStoringMode == EStoringMode::kSUBDIR) {
-    if (!fpFolderHist) { fpFolderHist = fpFolderRoot->AddFolder("histograms", "Histograms"); }
-    fpFolderHist->Add(pHist);
-  }
-  else if (fStoringMode == EStoringMode::kSAMEDIR) {
-    fpFolderRoot->Add(pHist);
-  }
-
   return pHist;
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-template<typename... Args>
-CbmQaTable* CbmQaIO::MakeTable(const char* nameBase, Args... args)
+template<typename T, typename... Args>
+T* CbmQaIO::MakeObject(const char* name, Args... args)
 {
-  TString name = fsPrefix + "_" + nameBase;
-  // Check, if the table with a given name was already created. If so, delete it
-  if (gROOT->FindObject(name)) {
-    LOG(warn) << fsRootFolderName << ": A previously created table \"" << name << "\" will be deleted";
-    CbmQaTable* pTable = (CbmQaTable*) gROOT->FindObject(name);
-    delete pTable;
+  // Resolve directory name and object name
+  TString sObjName   = name;
+  auto iLastSlashPos = static_cast<int>(sObjName.Last('/'));
+  TString sDirName   = sObjName(0, iLastSlashPos);
+  sObjName           = sObjName(iLastSlashPos + 1, sObjName.Length() - iLastSlashPos);
+
+  // Add unique prefix to the object name
+  sObjName = fsPrefix + "_" + sObjName;
+
+  // Add parent directory to the folder
+  if (fsRootFolderName.Length() != 0) { sDirName = fsRootFolderName + "/" + sDirName; }
+
+  // Check, if an object with the same name already exists
+  if (gROOT->FindObject(sObjName)) {
+    LOG(warn) << fsRootFolderName << ": A previously created object \"" << sObjName << "\" will be deleted";
+    auto* pObj = static_cast<T*>(gROOT->FindObject(sObjName));
+    delete pObj;
   }
 
-  // Create a new table
-  CbmQaTable* pTable = new CbmQaTable(name, args...);
+  // Create a new object
+  T* pObj = new T(sObjName, args...);
 
-  // Register table in folder
-  if (fStoringMode == EStoringMode::kSUBDIR) {
-    if (!fpFolderTable) { fpFolderTable = fpFolderRoot->AddFolder("tables", "Tables"); }
-    fpFolderTable->Add(pTable);
-  }
-  else if (fStoringMode == EStoringMode::kSAMEDIR) {
-    fpFolderRoot->Add(pTable);
-  }
+  // Register the object into an object list
+  fpvObjList->push_back(std::make_pair(static_cast<TObject*>(pObj), sDirName));
+  return pObj;
+}
 
+// ---------------------------------------------------------------------------------------------------------------------
+//
+template<typename... Args>
+CbmQaTable* CbmQaIO::MakeTable(const char* nameBase, Args... args)
+{
+  TString sFullName = EStoringMode::kSUBDIR == fStoringMode ? Form("tables/%s", nameBase) : nameBase;
+  auto* pTable      = MakeObject<CbmQaTable>(sFullName, args...);
   return pTable;
 }
 
diff --git a/core/qa/CbmQaTask.cxx b/core/qa/CbmQaTask.cxx
index 4bc40d55986ceb2c1ff3f7e4a91a0b77b4b04268..53effef64abb1c8aeb85396f887c81f295150efe 100644
--- a/core/qa/CbmQaTask.cxx
+++ b/core/qa/CbmQaTask.cxx
@@ -12,11 +12,13 @@
 
 #include "CbmQaCanvas.h"
 
+#include "FairRootFileSink.h"
 #include "FairRootManager.h"
 #include "FairRunAna.h"
-#include "FairSink.h"
 
 #include "TAxis.h"
+#include "TCanvas.h"
+#include "TF1.h"
 
 #include <array>
 
@@ -26,9 +28,10 @@ ClassImp(CbmQaTask);
 //
 CbmQaTask::CbmQaTask(const char* name, const char* prefix, int verbose, bool isMCUsed)
   : FairTask(name, verbose)
-  , CbmQaIO(name, prefix)
+  , CbmQaIO(prefix)
   , fbUseMC(isMCUsed)
 {
+  CbmQaIO::SetRootFolderName(name);
   fStoringMode = CbmQaIO::EStoringMode::kSUBDIR;  // mode of objects arrangement in the output file
 }
 
@@ -55,9 +58,20 @@ void CbmQaTask::Finish()
   InitCanvases();
 
   // Write the root folder to sinker
-  FairSink* pSink = FairRootManager::Instance()->GetSink();
-  LOG_IF(fatal, !pSink) << fName << ": sink file was not found";
-  pSink->WriteObject(fpFolderRoot, nullptr);
+  auto* pSink = FairRootManager::Instance()->GetSink();
+  LOG_IF(fatal, !pSink) << fName << ": output sink is undefined";
+  if (dynamic_cast<FairRootFileSink*>(pSink)) {
+    auto* pRootSink = static_cast<FairRootFileSink*>(pSink);
+    auto* pRootFile = pRootSink->GetRootFile();
+    if (!pRootFile->FindObjectAny("nEvents")) {
+      pRootFile->cd();
+      fNofEvents.Write();
+    }
+    this->WriteToFile(pRootSink->GetRootFile());
+  }
+  else {
+    LOG(warn) << fName << ": objects cannot be written into online sink (not implemented yet)";
+  }
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -90,9 +104,6 @@ InitStatus CbmQaTask::Init()
   LOG_IF(info, fVerbose > 1) << fName << ": initializing input data branches";
   res = std::max(res, InitDataBranches());
 
-  // ----- Initialize I/O
-  fpFolderRoot->Add(&fNofEvents);
-
   // ----- Initialize histograms
   LOG_IF(info, fVerbose > 1) << fName << ": initializing histograms";
   res = std::max(res, InitHistograms());
diff --git a/core/qa/CbmQaTask.h b/core/qa/CbmQaTask.h
index da033d11ddb5fbc8190855a876a5e936e063e6cd..e17a8b9fddd23cdd8b5cc16b11d14ebe06637d33 100644
--- a/core/qa/CbmQaTask.h
+++ b/core/qa/CbmQaTask.h
@@ -109,16 +109,6 @@ protected:
   /// Method to fill histograms per event or time-slice
   virtual void FillHistograms() {}
 
-  /// @brief Creates, initializes and registers a histogram, based on the configuration file
-  /// @tparam T    Type of the histogram (@note: should not be a pointer)
-  /// @param  name  Name of the histogram, stored in config
-  /// @param  id0   First index (optional)
-  /// @param  id1   Second index (optional)
-  /// @param  id2   Third index (optional)
-  /// @return  Pointer to the histogram object
-  template<typename T>
-  T* MakeHistoFromConfig(const char* name, int id0 = -1, int id1 = -1, int id2 = -1);
-
   /// Get current event number
   int GetEventNumber() const { return fNofEvents.GetVal(); }
 
@@ -141,7 +131,6 @@ private:
   /// @brief De-initializes this task
   void DeInitBase();
 
-
   bool fbUseMC     = false;  ///< Flag, if MC is used
 
   TParameter<int> fNofEvents {"nEvents", 0};  ///< Number of processed events
@@ -171,128 +160,4 @@ bool CbmQaTask::CheckRange(std::string_view name, const T& var, const T& lo, con
   return true;
 }
 
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-template<typename T>
-T* CbmQaTask::MakeHistoFromConfig(const char* nameBase, int id0, int id1, int id2)
-{
-  std::string name = std::string(fsPrefix.Data()) + "_" + nameBase;
-  if (id0 > -1) { name = std::regex_replace(name, std::regex("\\%0"), std::to_string(id0)); }
-  if (id1 > -1) { name = std::regex_replace(name, std::regex("\\%1"), std::to_string(id1)); }
-  if (id2 > -1) { name = std::regex_replace(name, std::regex("\\%2"), std::to_string(id2)); }
-
-  // Check, if the histogram with a given name was already created. If so, delete it
-  if (gROOT->FindObject(name.data())) {
-    LOG(warn) << fName << ": A histogram with name \"" << name << "\" was previously created and will be deleted now "
-              << "to avoid memory leaks";
-    T* pHist = (T*) gROOT->FindObject(name.data());
-    delete pHist;
-  }
-
-  T* pHist = nullptr;
-  // Create histogram
-  LOG_IF(fatal, !fpCurrentNode)
-    << fName << ": attempt to make a histogram (\"" << nameBase << "\") from configuration file, which was not "
-    << "defined. Please, provide configuration file with defined histogram list to the task via "
-    << "SetConfigName(filename) function.";
-  try {
-    const auto& node = (*fpCurrentNode)["histograms"][nameBase];
-    LOG_IF(fatal, !node) << fName << ": node for histogram \"" << nameBase
-                         << "\" was not defined in the configuration file";
-
-    std::string title = node["title"].as<std::string>("").data();
-    if (id0 > -1) { title = std::regex_replace(title, std::regex("\\%0"), std::to_string(id0)); }
-    if (id1 > -1) { title = std::regex_replace(title, std::regex("\\%1"), std::to_string(id1)); }
-    if (id2 > -1) { title = std::regex_replace(title, std::regex("\\%2"), std::to_string(id2)); }
-
-    // 1D-profiles
-    if constexpr (std::is_base_of_v<TProfile, T>) {
-      int nBinsX      = node["nbinsx"].as<int>();
-      double minX     = node["minx"].as<double>();
-      double maxX     = node["maxx"].as<double>();
-      double minY     = node["miny"].as<double>(0.);
-      double maxY     = node["maxy"].as<double>(0.);
-      std::string opt = node["opt"].as<std::string>("");
-      pHist           = new T(name.data(), title.data(), nBinsX, minX, maxX, minY, maxY, opt.data());
-    }
-    // 2D-profiles
-    else if constexpr (std::is_base_of_v<TProfile2D, T>) {
-      int nBinsX      = node["nbinsx"].as<int>();
-      double minX     = node["minx"].as<double>();
-      double maxX     = node["maxx"].as<double>();
-      int nBinsY      = node["nbinsy"].as<int>();
-      double minY     = node["miny"].as<double>();
-      double maxY     = node["maxy"].as<double>();
-      double minZ     = node["minz"].as<double>(0.);
-      double maxZ     = node["maxz"].as<double>(0.);
-      std::string opt = node["opt"].as<std::string>("");
-      pHist = new T(name.data(), title.data(), nBinsX, minX, maxX, nBinsY, minY, maxY, minZ, maxZ, opt.data());
-    }
-    // 3D-profiles
-    else if constexpr (std::is_base_of_v<TProfile3D, T>) {
-      int nBinsX      = node["nbinsx"].as<int>();
-      double minX     = node["minx"].as<double>();
-      double maxX     = node["maxx"].as<double>();
-      int nBinsY      = node["nbinsy"].as<int>();
-      double minY     = node["miny"].as<double>();
-      double maxY     = node["maxy"].as<double>();
-      int nBinsZ      = node["nbinsz"].as<int>();
-      double minZ     = node["minz"].as<double>();
-      double maxZ     = node["maxz"].as<double>();
-      std::string opt = node["opt"].as<std::string>("");
-      pHist = new T(name.data(), title.data(), nBinsX, minX, maxX, nBinsY, minY, maxY, nBinsZ, minZ, maxZ, opt.data());
-    }
-    // 2D-histograms
-    else if constexpr (std::is_base_of_v<TH2, T>) {
-      int nBinsX  = node["nbinsx"].as<int>();
-      double minX = node["minx"].as<double>();
-      double maxX = node["maxx"].as<double>();
-      int nBinsY  = node["nbinsy"].as<int>();
-      double minY = node["miny"].as<double>();
-      double maxY = node["maxy"].as<double>();
-      pHist       = new T(name.data(), title.data(), nBinsX, minX, maxX, nBinsY, minY, maxY);
-    }
-    // 3D-histograms + derived
-    else if constexpr (std::is_base_of_v<TH3, T>) {
-      int nBinsX  = node["nbinsx"].as<int>();
-      double minX = node["minx"].as<double>();
-      double maxX = node["maxx"].as<double>();
-      int nBinsY  = node["nbinsy"].as<int>();
-      double minY = node["miny"].as<double>();
-      double maxY = node["maxy"].as<double>();
-      int nBinsZ  = node["nbinsz"].as<int>();
-      double minZ = node["minz"].as<double>();
-      double maxZ = node["maxz"].as<double>();
-      pHist       = new T(name.data(), title.data(), nBinsX, minX, maxX, nBinsY, minY, maxY, nBinsZ, minZ, maxZ);
-    }
-    // 1D-histograms + derived
-    else if constexpr (std::is_base_of_v<TH1, T>) {
-      int nBinsX  = node["nbinsx"].as<int>();
-      double minX = node["minx"].as<double>();
-      double maxX = node["maxx"].as<double>();
-      pHist       = new T(name.data(), title.data(), nBinsX, minX, maxX);
-    }
-    // Other types are restricted
-    //else {
-    //  static_assert(false, "CbmQaTask::MakeTable: unsupported type given as a template parameter");
-    //}
-  }
-  catch (const YAML::InvalidNode& exc) {
-    LOG(fatal) << fName << ": error while reading the histogram \"" << nameBase << "\" properties from "
-               << "configuration file \"" << fsConfigName << "\". Please, check the file formatting. \n Tip: probably, "
-               << "there ara mistakes in the obligatory property names, for example, \"nbinsX\" or \"nXBins\" is "
-               << "used instead of \"nbinsx\" etc.";
-  }
-
-  // Register histogram in the folder
-  if (!fpFolderHist) { fpFolderHist = fpFolderRoot->AddFolder("histograms", "Histograms"); }
-  fpFolderHist->Add(pHist);
-
-  return pHist;
-}
-
-
-
-
 #endif  // CbmQaTask_h
diff --git a/core/qa/checker/CbmQaCheckerFileHandler.cxx b/core/qa/checker/CbmQaCheckerFileHandler.cxx
index 93c46c396a0822ca29b3079c7b24cf966d6b0daf..1ef18e081f22636866fbf6f5dcc0a178a3af3d6e 100644
--- a/core/qa/checker/CbmQaCheckerFileHandler.cxx
+++ b/core/qa/checker/CbmQaCheckerFileHandler.cxx
@@ -22,9 +22,11 @@
 #include "TH2.h"
 #include "TNamed.h"
 #include "TProfile.h"
+#include "TROOT.h"
 
 #include <boost/algorithm/string.hpp>
 
+#include <cstdlib>
 #include <iomanip>
 #include <sstream>
 #include <string>
@@ -160,12 +162,12 @@ void FileHandler::Process(Option_t* opt)
       for (int iVer = 0; iVer < nVersions; ++iVer) {
         if (fpObjDB->GetCmpResult(fDatasetID, fFileID, iObj, iVer)) { areDifferent = true; }
       }
-      if (true || areDifferent) { pObjHandler->CreateCanvases(); }
+      if (areDifferent) { pObjHandler->CreateCanvases(); }
     }
     pObjHandler->Write();
 
     // Clean memory
-    for (auto* pObj: vpObjects) {
+    for (auto* pObj : vpObjects) {
       if (pObj) {
         delete pObj;
         pObj = nullptr;
@@ -179,28 +181,9 @@ void FileHandler::Process(Option_t* opt)
 //
 TNamed* FileHandler::ReadObjectFromFile(TFile* pFile, const std::string& path) const
 {
-  TObject* pObj = pFile;
-  size_t iPos   = 0;  // Index of first symbol
-  size_t iNext  = 0;  // Index of last symbol
-  // Read object iteratively, running throug directories or folders, provided by path
-  while (iPos < path.size()) {
-    // get name
-    iNext = path.find_first_of('/', iPos);
-    if (iNext > path.size()) { iNext = path.size(); }
-    std::string part = path.substr(iPos, iNext - iPos);  // short name of next object/directory/folder in the path
-    iPos             = iNext + 1;
-    if (!part.size()) { continue; }
-
-    // test TDirectoryFile
-    if (dynamic_cast<TDirectoryFile*>(pObj)) {
-      auto* pDir = static_cast<TDirectoryFile*>(pObj);
-      pObj       = pDir->FindObjectAny(part.data());
-    }
-    // test TFolder
-    else if (dynamic_cast<TFolder*>(pObj)) {
-      auto* pDir = static_cast<TFolder*>(pObj);
-      pObj       = pDir->FindObjectAny(part.data());
-    }
-  }
-  return dynamic_cast<TNamed*>(pObj);
+  int iPosSlash        = path.find_last_of('/') + 1;
+  std::string baseName = path.substr(iPosSlash, path.size());
+  std::string pathName = path.substr(0, iPosSlash);
+  if (pathName.size() > 0) { pFile->cd(pathName.c_str()); }
+  return dynamic_cast<TNamed*>(pFile->FindObjectAny(baseName.c_str()));
 }
diff --git a/core/qa/checker/CbmQaCheckerObjectHandler.cxx b/core/qa/checker/CbmQaCheckerObjectHandler.cxx
index 180f5e59f3d22f589ccd2c143d484f1beb9a5c4c..336573ef2dccfcd8bf4929820e1c13ac356da03a 100644
--- a/core/qa/checker/CbmQaCheckerObjectHandler.cxx
+++ b/core/qa/checker/CbmQaCheckerObjectHandler.cxx
@@ -30,9 +30,9 @@ ObjectHandler::ObjectHandler(int iObject, int iFile, int iDataset, const char* o
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-ObjectHandler::~ObjectHandler() 
+ObjectHandler::~ObjectHandler()
 {
-  for (auto* pObj: fvpObjects) {
+  for (auto* pObj : fvpObjects) {
     if (pObj) {
       delete pObj;
       pObj = nullptr;
diff --git a/reco/L1/qa/CbmCaOutputQa.cxx b/reco/L1/qa/CbmCaOutputQa.cxx
index affd3861bdbcee57585caa1d8046bd61cce62e9a..4547ea539c2206afe1f856d1814c06f2d2b94ea2 100644
--- a/reco/L1/qa/CbmCaOutputQa.cxx
+++ b/reco/L1/qa/CbmCaOutputQa.cxx
@@ -486,7 +486,8 @@ InitStatus OutputQa::InitHistograms()
     if (!fvbTrackTypeOn[type]) { return; }
     bool bUseMC              = IsMCUsed() && !bSuppressMC;
     fvsTrackTypeName[type]   = typeName;
-    fvpTrackHistograms[type] = std::make_unique<TrackTypeQa>(typeName, fsPrefix.Data(), bUseMC, fpFolderRoot);
+    fvpTrackHistograms[type] = std::make_unique<TrackTypeQa>(typeName, fsPrefix.Data(), bUseMC, fpvObjList);
+    fvpTrackHistograms[type]->SetRootFolderName(fsRootFolderName + "/" + typeName);
     fvpTrackHistograms[type]->SetTitle(title);
     fvpTrackHistograms[type]->RegisterParameters(fpParameters);
     fvpTrackHistograms[type]->RegisterRecoHits(fvHits);
diff --git a/reco/L1/qa/CbmCaTrackFitQa.cxx b/reco/L1/qa/CbmCaTrackFitQa.cxx
index 75bf0ff43c624ec0d2ed154d2e59023d297704c7..35b51d194858617b55adf48fee2034b5244c5dfe 100644
--- a/reco/L1/qa/CbmCaTrackFitQa.cxx
+++ b/reco/L1/qa/CbmCaTrackFitQa.cxx
@@ -34,8 +34,8 @@ using cbm::ca::TrackFitQa;
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-TrackFitQa::TrackFitQa(const char* pointTag, const char* prefixName, TFolder* pParentFolder)
-  : CbmQaIO(pointTag, Form("%s_%s", prefixName, pointTag), pParentFolder)
+TrackFitQa::TrackFitQa(const char* pointTag, const char* prefix, std::shared_ptr<ObjList_t> pObjList)
+  : CbmQaIO(Form("%s_%s", prefix, pointTag), pObjList)
 {
   fStoringMode = EStoringMode::kSAMEDIR;
 }
diff --git a/reco/L1/qa/CbmCaTrackFitQa.h b/reco/L1/qa/CbmCaTrackFitQa.h
index 051d200ba59d30d7ad47355d48c18fa62ce64666..a76ccd2426c353f44f8f26626bbaa79aee2fec63 100644
--- a/reco/L1/qa/CbmCaTrackFitQa.h
+++ b/reco/L1/qa/CbmCaTrackFitQa.h
@@ -69,10 +69,10 @@ namespace cbm::ca
   class TrackFitQa : public CbmQaIO {
   public:
     /// @brief Constructor
-    /// @param pointTag       Tag for point, in which the parameters are analyzed
-    /// @param prefixName     Name of unique prefix
-    /// @param pParentFolder  Pointer to parent folder
-    TrackFitQa(const char* pointTag, const char* prefixName, TFolder* pParentFolder);
+    /// @param pointTag  Tag for point, in which the parameters are analyzed
+    /// @param prefix    Name of unique prefix
+    /// @param pObjList  List of registered ROOT objects
+    TrackFitQa(const char* pointTag, const char* prefix, std::shared_ptr<ObjList_t> pObjList);
 
     /// @brief Destructor
     ~TrackFitQa() = default;
diff --git a/reco/L1/qa/CbmCaTrackTypeQa.cxx b/reco/L1/qa/CbmCaTrackTypeQa.cxx
index d304b8477921ace69826ea7c835edb58ee515e66..295b18de6806aab4a879ef7da14f744fd59458f7 100644
--- a/reco/L1/qa/CbmCaTrackTypeQa.cxx
+++ b/reco/L1/qa/CbmCaTrackTypeQa.cxx
@@ -21,8 +21,8 @@ using cbm::ca::TrackTypeQa;
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-TrackTypeQa::TrackTypeQa(const char* typeName, const char* prefixName, bool bUseMC, TFolder* pParentFolder)
-  : CbmQaIO(typeName, Form("%s_%s", prefixName, typeName), pParentFolder)
+TrackTypeQa::TrackTypeQa(const char* typeName, const char* prefix, bool bUseMC, std::shared_ptr<ObjList_t> pObjList)
+  : CbmQaIO(Form("%s_%s", prefix, typeName), pObjList)
   , fbUseMC(bUseMC)
 {
   fStoringMode = EStoringMode::kSAMEDIR;
@@ -154,17 +154,20 @@ void TrackTypeQa::Init()
     //
     // ** Track fit parameter properties (residuals and pulls) **
     //
-    fpFitQaFirstHit = std::make_unique<TrackFitQa>("fst_hit", fsPrefix, fpFolderRoot);
+    fpFitQaFirstHit = std::make_unique<TrackFitQa>("fst_hit", fsPrefix, fpvObjList);
+    fpFitQaFirstHit->SetRootFolderName(fsRootFolderName + "/fst_hit");
     fpFitQaFirstHit->SetTitle("First hit");
     fpFitQaFirstHit->Init();
 
-    fpFitQaLastHit = std::make_unique<TrackFitQa>("lst_hit", fsPrefix, fpFolderRoot);
+    fpFitQaLastHit = std::make_unique<TrackFitQa>("lst_hit", fsPrefix, fpvObjList);
+    fpFitQaLastHit->SetRootFolderName(fsRootFolderName + "/lst_hit");
     fpFitQaLastHit->SetTitle("Last hit");
     fpFitQaLastHit->SetResidualHistoProperties(ETrackParType::kX, 200, -0.4, +0.4);
     fpFitQaLastHit->SetResidualHistoProperties(ETrackParType::kY, 200, -0.8, +0.8);
     fpFitQaLastHit->Init();
 
-    fpFitQaVertex = std::make_unique<TrackFitQa>("vertex", fsPrefix, fpFolderRoot);
+    fpFitQaVertex = std::make_unique<TrackFitQa>("vertex", fsPrefix, fpvObjList);
+    fpFitQaVertex->SetRootFolderName(fsRootFolderName + "/vertex");
     fpFitQaVertex->SetTitle("Vertex");
     fpFitQaVertex->Init();
   }
diff --git a/reco/L1/qa/CbmCaTrackTypeQa.h b/reco/L1/qa/CbmCaTrackTypeQa.h
index 5e527a31c4d8caade8a1d4ed9402374ad25a2d58..f64ef78bb82d6340b05d92e66f9975193dc63636 100644
--- a/reco/L1/qa/CbmCaTrackTypeQa.h
+++ b/reco/L1/qa/CbmCaTrackTypeQa.h
@@ -46,8 +46,8 @@ namespace cbm::ca
     /// @note  Track type is stored as a root directory name in the CbmQaIO base class
     /// @param prefixName Name of unique prefix
     /// @param bUseMC     Flag: true - MC is used
-    /// @param pParentFolder Pointer to parent folder
-    TrackTypeQa(const char* typeName, const char* prefixName, bool bUseMC, TFolder* pParentFolder);
+    /// @param pObjList   List of registered objects
+    TrackTypeQa(const char* typeName, const char* prefixName, bool bUseMC, std::shared_ptr<ObjList_t> pObjList);
 
     /// @brief Destructor
     ~TrackTypeQa() = default;