diff --git a/reco/kf/CMakeLists.txt b/reco/kf/CMakeLists.txt
index 0bc036a5d297f3619c0ae68f70c68776414cf240..9a5e8b40448fcddabfdd3c1ebce03f8acd373d32 100644
--- a/reco/kf/CMakeLists.txt
+++ b/reco/kf/CMakeLists.txt
@@ -3,6 +3,7 @@ set(INCLUDE_DIRECTORIES
 )
 
 set(SRCS 
+  ${CMAKE_CURRENT_SOURCE_DIR}/CbmKfTarget.cxx
   ${CMAKE_CURRENT_SOURCE_DIR}/CbmKfTrackingSetupInitializer.cxx
 )
 
@@ -68,6 +69,7 @@ install(TARGETS CbmKf DESTINATION lib)
 
 install(
   FILES
+    CbmKfTarget.h
     CbmKfTrackingSetupInitializer.h
   DESTINATION
     include/
diff --git a/reco/kf/CbmKfTarget.cxx b/reco/kf/CbmKfTarget.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a572edec2a9abc90a5807ed8c76c1b6a2e7c44b1
--- /dev/null
+++ b/reco/kf/CbmKfTarget.cxx
@@ -0,0 +1,97 @@
+/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   CbmKfTarget.h
+/// \brief  Target property initialization and access in CBM (source)
+/// \since  02.09.2024
+/// \author Sergei Zharko <s.zharko@gsi.de>
+
+// TODO: Move this class somewhere in the cbmroot/core
+
+#include "CbmKfTarget.h"
+
+#include "Logger.h"
+#include "TGeoManager.h"
+#include "TGeoNode.h"
+#include "TGeoTube.h"
+#include "TGeoVolume.h"
+
+#include <iomanip>
+
+using cbm::kf::Target;
+
+Target* Target::fpInstance{nullptr};
+std::mutex Target::fMutex;
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+Target* Target::Instance()
+{
+  std::lock_guard<std::mutex> lock(fMutex);
+  if (!fpInstance) {
+    fpInstance = new Target();
+    fpInstance->Init();
+  }
+  return fpInstance;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void Target::Init()
+{
+  if (!gGeoManager) {
+    throw std::logic_error("cbm::kf::Target: the TGeoManager instance is not initialized on this step. Please be "
+                           "ensured to call the Target::Init() after the TGeoManager initialization.");
+  }
+
+  std::function<void(TString&, TGeoNode*)> FindTargetNode = [&](TString& targetPath, TGeoNode* targetNode) -> void {
+    if (!targetNode) {  // init at the top of the tree
+      targetNode = gGeoManager->GetTopNode();
+      targetPath = "/" + TString(targetNode->GetName());
+    }
+
+    if (TString(targetNode->GetName()).Contains("target")) {
+      return;
+    }
+
+    for (Int_t iNode = 0; iNode < targetNode->GetNdaughters(); ++iNode) {
+      TGeoNode* newNode = targetNode->GetDaughter(iNode);
+      TString newPath   = targetPath + "/" + newNode->GetName();
+      FindTargetNode(newPath, newNode);
+      if (newNode) {
+        targetPath = newPath;
+        targetNode = newNode;
+        return;
+      }
+    }
+    targetPath = "";
+    targetNode = nullptr;
+  };
+
+  TString targetPath;
+  TGeoNode* pTargetNode{nullptr};
+  FindTargetNode(targetPath, pTargetNode);
+
+  if (!pTargetNode) {
+    throw std::runtime_error("cbm::kf::Target: the target node is not found in the setup");
+  }
+
+  Double_t local[3]  = {0., 0., 0.};  // target centre, local c.s.
+  Double_t global[3] = {0};           // target centre, global c.s.
+  gGeoManager->cd(targetPath);
+  gGeoManager->GetCurrentMatrix()->LocalToMaster(local, global);
+  fX = global[0];
+  fY = global[1];
+  fZ = global[2];
+
+  if (const auto* pTube = dynamic_cast<TGeoTube*>(pTargetNode->GetVolume()->GetShape())) {
+    fDz   = pTube->GetDz();
+    fRmax = pTube->GetRmax();
+  }
+  else {
+    throw std::logic_error("cbm::kf::Target: target is supposed to be a Tube, but it is not. Please, "
+                           "provide a proper handling of the new target shape (return it's reference central point "
+                           "and half of its thickness)");
+  }
+}
diff --git a/reco/kf/CbmKfTarget.h b/reco/kf/CbmKfTarget.h
new file mode 100644
index 0000000000000000000000000000000000000000..2440ad513e264b7b2bbd25075174e40661e65ad8
--- /dev/null
+++ b/reco/kf/CbmKfTarget.h
@@ -0,0 +1,68 @@
+/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   CbmKfTarget.h
+/// \brief  Target property initialization and access in CBM (header)
+/// \since  02.09.2024
+/// \author Sergei Zharko <s.zharko@gsi.de>
+
+// TODO: Move this class somewhere in the cbmroot/core
+
+#pragma once
+
+#include "KfDefs.h"
+
+#include <mutex>
+
+namespace cbm::kf
+{
+  /// \class Target
+  /// \brief CBM target accessor and property handler
+  class Target {
+   public:
+    /// \brief Gets target center x-coordinate [cm]
+    double GetX() const { return fX; }
+
+    /// \brief Gets target center y-coordinate [cm]
+    double GetY() const { return fY; }
+
+    /// \brief Gets target center z-coordinate [cm]
+    double GetZ() const { return fZ; }
+
+    /// \brief Gets target half thickness [cm]
+    double GetDz() const { return fDz; }
+
+    /// \brief Gets target transverse size [cm]
+    double GetRmax() const { return fRmax; }
+
+    /// \brief Instance access
+    static Target* Instance();
+
+    // Copy and move elimination
+    Target(const Target&) = delete;
+    Target(Target&&)      = delete;
+    Target& operator=(const Target&) = delete;
+    Target& operator=(Target&&) = delete;
+
+   protected:
+    /// \brief Default constructor
+    Target() = default;
+
+    /// \brief Destructor
+    ~Target() = default;
+
+    /// \brief Target initializer
+    void Init();
+
+    double fX{cbm::algo::kf::defs::Undef<double>};     ///< reference x-coordinate of the target position [cm]
+    double fY{cbm::algo::kf::defs::Undef<double>};     ///< reference y-coordinate of the target position [cm]
+    double fZ{cbm::algo::kf::defs::Undef<double>};     ///< reference z-coordinate of the target position [cm]
+    double fDz{cbm::algo::kf::defs::Undef<double>};    ///< target half-thickness [cm]
+    double fRmax{cbm::algo::kf::defs::Undef<double>};  ///< target transverse size [cm]
+
+   private:
+    static Target* fpInstance;
+    static std::mutex fMutex;
+  };
+}  // namespace cbm::kf
diff --git a/reco/kf/CbmKfTrackingSetupInitializer.cxx b/reco/kf/CbmKfTrackingSetupInitializer.cxx
index bb6f465d3a1f0a1307093f487822b5d0055259a2..4a418301bca9f8fe4d37442764546ae914f4a346 100644
--- a/reco/kf/CbmKfTrackingSetupInitializer.cxx
+++ b/reco/kf/CbmKfTrackingSetupInitializer.cxx
@@ -9,6 +9,7 @@
 
 #include "CbmKfTrackingSetupInitializer.h"
 
+#include "CbmKfTarget.h"
 #include "CbmMuchTrackingInterface.h"
 #include "CbmMvdTrackingInterface.h"
 #include "CbmSetup.h"
@@ -19,10 +20,6 @@
 #include "FairRunAna.h"
 #include "KfDefs.h"
 #include "KfMaterialMapCreator.h"
-#include "TGeoManager.h"
-#include "TGeoNode.h"
-#include "TGeoTube.h"
-#include "TGeoVolume.h"
 
 #include <functional>
 
@@ -85,26 +82,26 @@ try {
     CollectStations(fbUseTof ? CbmTofTrackingInterface::Instance() : nullptr);
 
     // Retriev target properties
-    // TODO: Provide some beter handler for target properties access
-    auto [targX, targY, targZ, targHalfThick, targRadius] = this->GetTarget();
+    const auto* pTarget = Target::Instance();
 
     // Init material map creator
     MaterialMapCreator materialCreator{};
     materialCreator.SetSafeMaterialInitialization(kMatCreatorSafeMode);
-    materialCreator.SetDoRadialProjection(targZ);
+    materialCreator.SetDoRadialProjection(pTarget->GetZ());
     materialCreator.SetNraysPerDim(kMatCreatorNrays);
 
     // Target initialization
-    double zLast = targZ + targHalfThick + kTargMaterialOffset;  // z-coordinate of the target material upper limit
+    double zLast =
+      pTarget->GetZ() + pTarget->GetDz() + kTargMaterialOffset;  // z-coordinate of the target material upper limit
     {
       // Material of the target
-      double xyMax{1.3 * targRadius};
+      double xyMax{1.3 * pTarget->GetRmax()};
       int nBins{std::min(static_cast<int>(std::ceil(2. * xyMax / kMatCreatorPitch)), kMatCreatorMaxNbins)};
       assert(nBins > 0);
-      double zFirst{targZ - targHalfThick};  // z-coordinate of the target material lower limit
+      double zFirst{pTarget->GetZ() + pTarget->GetDz()};  // z-coordinate of the target material lower limit
       LOG(info) << "- collecting target material (z = " << zFirst << " - " << zLast << ", size = " << xyMax << ")\n";
-      this->SetTargetProperties(targX, targY, targZ, kTargFieldInitStep,
-                                materialCreator.GenerateMaterialMap(targZ, zFirst, zLast, xyMax, nBins));
+      this->SetTargetProperties(pTarget->GetX(), pTarget->GetY(), pTarget->GetZ(), kTargFieldInitStep,
+                                materialCreator.GenerateMaterialMap(pTarget->GetZ(), zFirst, zLast, xyMax, nBins));
     }
 
     // Material and field layers initialization
@@ -142,59 +139,3 @@ void TrackingSetupInitializer::Use(bool mvd, bool sts, bool much, bool trd, bool
   fbUseTrd  = trd;
   fbUseTof  = tof;
 }
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-std::tuple<double, double, double, double, double> TrackingSetupInitializer::GetTarget()
-{
-  std::function<void(TString&, TGeoNode*)> FindTargetNode = [&](TString& targetPath, TGeoNode* targetNode) -> void {
-    if (!targetNode) {  // init at the top of the tree
-      targetNode = gGeoManager->GetTopNode();
-      targetPath = "/" + TString(targetNode->GetName());
-    }
-
-    if (TString(targetNode->GetName()).Contains("target")) {
-      return;
-    }
-
-    for (Int_t iNode = 0; iNode < targetNode->GetNdaughters(); ++iNode) {
-      TGeoNode* newNode = targetNode->GetDaughter(iNode);
-      TString newPath   = targetPath + "/" + newNode->GetName();
-      FindTargetNode(newPath, newNode);
-      if (newNode) {
-        targetPath = newPath;
-        targetNode = newNode;
-        return;
-      }
-    }
-    targetPath = "";
-    targetNode = nullptr;
-  };
-
-  TString targetPath;
-  TGeoNode* pTargetNode{nullptr};
-  FindTargetNode(targetPath, pTargetNode);
-
-  if (!pTargetNode) {
-    throw std::runtime_error("kf::TrackingSetupInitializer: target node is not found in the setup");
-  }
-
-  Double_t local[3] = {0., 0., 0.};  // target centre, local c.s.
-  Double_t global[3];                // target centre, global c.s.
-  gGeoManager->cd(targetPath);
-  gGeoManager->GetCurrentMatrix()->LocalToMaster(local, global);
-
-  double halfThick{cbm::algo::kf::defs::Undef<double>};
-  double outerRadius{cbm::algo::kf::defs::Undef<double>};
-  if (const auto* pTube = dynamic_cast<TGeoTube*>(pTargetNode->GetVolume()->GetShape())) {
-    halfThick   = pTube->GetDz();
-    outerRadius = pTube->GetRmax();
-  }
-  else {
-    throw std::logic_error("kf::TrackingSetupInitializer: target is supposed to be a Tube, but it is not. Please, "
-                           "provide a proper handling of the new target shape (return it's reference central point "
-                           "and half of its thickness)");
-  }
-
-  return std::make_tuple(local[0], local[1], local[2], halfThick, outerRadius);
-}
diff --git a/reco/kf/CbmKfTrackingSetupInitializer.h b/reco/kf/CbmKfTrackingSetupInitializer.h
index 62f22cb68dd86bdd651eefee671ea0ea961f97ed..4148c1ff636c7410c302217dbf94e6a21fb17185 100644
--- a/reco/kf/CbmKfTrackingSetupInitializer.h
+++ b/reco/kf/CbmKfTrackingSetupInitializer.h
@@ -19,10 +19,12 @@ namespace cbm::kf
   /// \brief Encapsulation of the kf::Setup initialization routines for CBM
   class TrackingSetupInitializer : public cbm::algo::kf::SetupInitializer {
    public:
-    /// \brief  Default constructor
-    TrackingSetupInitializer();
-
     /// \brief  Initializes the instance
+    /// \param  mvd   Is MVD used
+    /// \param  sts   Is STS used
+    /// \param  much  Is MuCh used
+    /// \param  trd   Is TRD used
+    /// \param  tof   Is TOF used
     bool InitProperties() override;
 
     /// \brief  Enables/disables detector subsystems in the setup
@@ -34,18 +36,13 @@ namespace cbm::kf
     void Use(bool mvd, bool sts, bool much, bool trd, bool tof);
 
    private:
-    /// \brief Gets target position and half-thickness
-    /// \return  tuple(x, y, z, half-thickness, outer radius) [cm]
-    std::tuple<double, double, double, double, double> GetTarget();
-
     // Material map creator properties (TODO: Provide setters, if needed)
-    static constexpr double kMatCreatorPitch{0.1};    ///< Material budget map minimal bin size [cm]
-    static constexpr int kMatCreatorMaxNbins{100};    ///< Max number of bins in the material budget map in x(y) axis
-    static constexpr int kMatCreatorNrays{3};         ///< Number of rays per dimension for the material budget
-    static constexpr bool kMatCreatorSafeMode{true};  ///< Safe mode of the material map creation
-    static constexpr double kTargFieldInitStep{2.5};  ///< Step between nodes in the target field initialization [cm]
-    static constexpr double kTargMaterialOffset{
-      0.2};  ///< Offset between target volume and the corresponding material zMax [cm]
+    static constexpr double kMatCreatorPitch{0.1};     ///< Material budget map minimal bin size [cm]
+    static constexpr int kMatCreatorMaxNbins{100};     ///< Max number of bins in the material budget map in x(y) axis
+    static constexpr int kMatCreatorNrays{3};          ///< Number of rays per dimension for the material budget
+    static constexpr bool kMatCreatorSafeMode{true};   ///< Safe mode of the material map creation
+    static constexpr double kTargFieldInitStep{2.5};   ///< Step between nodes in the target field initialization [cm]
+    static constexpr double kTargMaterialOffset{0.2};  ///< Offset between target upper limit and its material zMax [cm]
 
     bool fbUseMvd{false};   ///< Are MVD stations included in the tracking setup
     bool fbUseSts{false};   ///< Are STS stations included in the tracking setup