diff --git a/Core/include/Acts/Geometry/BoundarySurfaceT.hpp b/Core/include/Acts/Geometry/BoundarySurfaceT.hpp
index 6dd3dbe8b14b2080d863193f8ddbe27a874cb99d..52bb1f2283f7c5efa06b949ced79e69b1ce4ea44 100644
--- a/Core/include/Acts/Geometry/BoundarySurfaceT.hpp
+++ b/Core/include/Acts/Geometry/BoundarySurfaceT.hpp
@@ -127,17 +127,18 @@ class BoundarySurfaceT {
   /// Virtual Destructor
   virtual ~BoundarySurfaceT() = default;
 
-  /// Helper metho: attach a Volume to this BoundarySurfaceT
-  /// this si done during the geometry construction and only called by
+ protected:
+  /// Helper method: attach a Volume to this BoundarySurfaceT
+  /// this is done during the geometry construction and only called by
   /// the friend templated volume
   ///
   /// @param gctx The current geometry context object, e.g. alignment
   /// @param volume The volume to be attached
   /// @param inout The boundary orientation @todo update to along/opposite
-  void attachVolume(VolumePtr volume, BoundaryOrientation inout);
+  void attachVolume(const T* volume, BoundaryOrientation inout);
 
-  /// Helper metho: attach a Volume to this BoundarySurfaceT
-  /// this si done during the geometry construction and only called by
+  /// Helper method: attach a Volume to this BoundarySurfaceT
+  /// this is done during the geometry construction and only called by
   /// the friend templated volume
   ///
   /// @param volumes The volume array to be attached
@@ -164,12 +165,12 @@ inline const Surface& BoundarySurfaceT<T>::surfaceRepresentation() const {
 }
 
 template <class T>
-void BoundarySurfaceT<T>::attachVolume(VolumePtr volume,
+void BoundarySurfaceT<T>::attachVolume(const T* volume,
                                        BoundaryOrientation inout) {
   if (inout == insideVolume) {
-    m_insideVolume = volume.get();
+    m_insideVolume = volume;
   } else {
-    m_outsideVolume = volume.get();
+    m_outsideVolume = volume;
   }
 }
 
diff --git a/Core/include/Acts/Geometry/CuboidVolumeBuilder.hpp b/Core/include/Acts/Geometry/CuboidVolumeBuilder.hpp
index 64f0fa9fbc6f398d87ce44641af74f782f8b5f64..417bc2f7ba109740909096ff5f3ad31d5a4e061d 100644
--- a/Core/include/Acts/Geometry/CuboidVolumeBuilder.hpp
+++ b/Core/include/Acts/Geometry/CuboidVolumeBuilder.hpp
@@ -13,6 +13,7 @@
 #include <vector>
 #include "Acts/Geometry/GeometryContext.hpp"
 #include "Acts/Geometry/ITrackingVolumeBuilder.hpp"
+#include "Acts/Utilities/BinningType.hpp"
 #include "Acts/Utilities/Definitions.hpp"
 
 namespace Acts {
@@ -79,6 +80,10 @@ class CuboidVolumeBuilder : public ITrackingVolumeBuilder {
     std::vector<LayerConfig> layerCfg;
     // Stored layers
     std::vector<std::shared_ptr<const Layer>> layers;
+    // Configurations of confined volumes
+    std::vector<VolumeConfig> volumeCfg;
+    // Stored confined volumes
+    std::vector<std::shared_ptr<TrackingVolume>> trackingVolumes;
     // Name of the volume
     std::string name = "Volume";
     // Material
@@ -152,6 +157,9 @@ class CuboidVolumeBuilder : public ITrackingVolumeBuilder {
   std::pair<double, double> binningRange(const GeometryContext& gctx,
                                          const VolumeConfig& cfg) const;
 
+  void sortVolumes(std::vector<std::pair<TrackingVolumePtr, Vector3D>>& tapVec,
+                   BinningValue bValue) const;
+
   /// @brief This function builds a world TrackingVolume based on a given
   /// configuration
   ///
@@ -167,5 +175,4 @@ class CuboidVolumeBuilder : public ITrackingVolumeBuilder {
   /// Configuration of the world volume
   Config m_cfg;
 };
-
-}  // namespace Acts
+}  // namespace Acts
\ No newline at end of file
diff --git a/Core/include/Acts/Geometry/CylinderLayer.hpp b/Core/include/Acts/Geometry/CylinderLayer.hpp
index 1360143431fa61d88acd5e8c6bfb15157ed075f9..02a2b9622866b0f5f9934e4301355e2a602512d2 100644
--- a/Core/include/Acts/Geometry/CylinderLayer.hpp
+++ b/Core/include/Acts/Geometry/CylinderLayer.hpp
@@ -108,4 +108,4 @@ class CylinderLayer : public CylinderSurface, public Layer {
   CylinderLayer(const CylinderLayer& cla, const Transform3D& shift);
 };
 
-}  // namespace Acts
+}  // namespace Acts
\ No newline at end of file
diff --git a/Core/include/Acts/Geometry/CylinderVolumeBuilder.hpp b/Core/include/Acts/Geometry/CylinderVolumeBuilder.hpp
index 68805d61332cea43cd56d939bcc71774f9e6e3d9..fbfd797747b822614a0f189c40d5461a1b0874b5 100644
--- a/Core/include/Acts/Geometry/CylinderVolumeBuilder.hpp
+++ b/Core/include/Acts/Geometry/CylinderVolumeBuilder.hpp
@@ -17,6 +17,7 @@
 #include <string>
 
 #include "Acts/Geometry/GeometryContext.hpp"
+#include "Acts/Geometry/IConfinedTrackingVolumeBuilder.hpp"
 #include "Acts/Geometry/ILayerBuilder.hpp"
 #include "Acts/Geometry/ITrackingVolumeBuilder.hpp"
 #include "Acts/Geometry/ITrackingVolumeHelper.hpp"
@@ -53,13 +54,14 @@ enum WrappingCondition {
 
 /// VolumeConfig struct to understand the layer config
 struct VolumeConfig {
-  bool present{false};   ///< layers are present
-  bool wrapping{false};  ///< in what way they are binned
-  double rMin;           ///< min parameter r
-  double rMax;           ///< max parameter r
-  double zMin;           ///< min parameter z
-  double zMax;           ///< max parameter z
-  LayerVector layers;    ///< the layers you have
+  bool present{false};                  ///< layers are present
+  bool wrapping{false};                 ///< in what way they are binned
+  double rMin;                          ///< min parameter r
+  double rMax;                          ///< max parameter r
+  double zMin;                          ///< min parameter z
+  double zMax;                          ///< max parameter z
+  LayerVector layers;                   ///< the layers you have
+  MutableTrackingVolumeVector volumes;  ///< the confined volumes you have
 
   /// Default constructor
   VolumeConfig()
@@ -474,14 +476,15 @@ class CylinderVolumeBuilder : public ITrackingVolumeBuilder {
     std::shared_ptr<const ITrackingVolumeHelper> trackingVolumeHelper = nullptr;
     /// the string based indenfication
     std::string volumeName = "";
-    /// The dimensions of the manually created world
-    std::vector<double> volumeDimension = {};
     /// the world material
     std::shared_ptr<const IVolumeMaterial> volumeMaterial = nullptr;
     /// build the volume to the beam line
     bool buildToRadiusZero = false;
     /// needed to build layers within the volume
     std::shared_ptr<const ILayerBuilder> layerBuilder = nullptr;
+    /// needed to build confined volumes within the volume
+    std::shared_ptr<const IConfinedTrackingVolumeBuilder> ctVolumeBuilder =
+        nullptr;
     /// the additional envelope in R to create rMin, rMax
     std::pair<double, double> layerEnvelopeR = {1. * UnitConstants::mm,
                                                 1. * UnitConstants::mm};
@@ -538,14 +541,15 @@ class CylinderVolumeBuilder : public ITrackingVolumeBuilder {
   /// @param [in] newLogger is the logging istance to be set
   void setLogger(std::unique_ptr<const Logger> newLogger);
 
-  /// Analyze the layer config to gather needed dimension
+  /// Analyze the config to gather needed dimension
   ///
   /// @param [in] gctx the geometry context for this building
   /// @param [in] lVector is the vector of layers that are parsed
   ///
   /// @return a VolumeConfig representing this layer
-  VolumeConfig analyzeLayers(const GeometryContext& gctx,
-                             const LayerVector& lVector) const;
+  VolumeConfig analyzeContent(
+      const GeometryContext& gctx, const LayerVector& lVector,
+      const MutableTrackingVolumeVector& mtvVector) const;
 
  private:
   /// Configuration struct
@@ -583,4 +587,4 @@ inline CylinderVolumeBuilder::Config CylinderVolumeBuilder::getConfiguration()
   return m_cfg;
 }
 
-}  // namespace Acts
+}  // namespace Acts
\ No newline at end of file
diff --git a/Core/include/Acts/Geometry/CylinderVolumeHelper.hpp b/Core/include/Acts/Geometry/CylinderVolumeHelper.hpp
index d5de14615305969006c5050fce2d0c104610fae0..6188aaca6b6f46051d8c39e993dcb259da14d328 100644
--- a/Core/include/Acts/Geometry/CylinderVolumeHelper.hpp
+++ b/Core/include/Acts/Geometry/CylinderVolumeHelper.hpp
@@ -80,6 +80,7 @@ class CylinderVolumeHelper : public ITrackingVolumeHelper {
   /// together with the volume enevlope parameters
   /// @param volumeMaterial material properties for this TrackingVolume
   /// @param volumeBounds: confinement of this TrackingVolume
+  /// @param mtvVector (optiona) Vector of confined TrackingVolumes
   /// @param transform (optional) placement of this TrackingVolume
   /// @param volumeName  volume name to be given
   /// @param bType (optional) BinningType - arbitrary(default) or equidistant
@@ -88,7 +89,7 @@ class CylinderVolumeHelper : public ITrackingVolumeHelper {
   MutableTrackingVolumePtr createTrackingVolume(
       const GeometryContext& gctx, const LayerVector& layers,
       std::shared_ptr<const IVolumeMaterial> volumeMaterial,
-      VolumeBoundsPtr volumeBounds,
+      VolumeBoundsPtr volumeBounds, MutableTrackingVolumeVector mtvVector = {},
       std::shared_ptr<const Transform3D> transform = nullptr,
       const std::string& volumeName = "UndefinedVolume",
       BinningType bType = arbitrary) const override;
@@ -100,6 +101,7 @@ class CylinderVolumeHelper : public ITrackingVolumeHelper {
   /// if no bounds or HepTransform is given, they define the size
   /// together with the volume enevlope parameters
   /// @param volumeMaterial material properties for this TrackingVolume
+  /// @param mtvVector Vector of confined TrackingVolumes
   /// @param rMin minimum radius
   /// @param rMax maximum radius
   /// @param zMin minimum z
@@ -110,6 +112,7 @@ class CylinderVolumeHelper : public ITrackingVolumeHelper {
   /// @return shared pointer to a new TrackingVolume
   MutableTrackingVolumePtr createTrackingVolume(
       const GeometryContext& gctx, const LayerVector& layers,
+      MutableTrackingVolumeVector mtvVector,
       std::shared_ptr<const IVolumeMaterial> volumeMaterial, double rMin,
       double rMax, double zMin, double zMax,
       const std::string& volumeName = "UndefinedVolume",
@@ -119,6 +122,7 @@ class CylinderVolumeHelper : public ITrackingVolumeHelper {
   /// @note this TrackingVolume is restricted to Translation only
   ///
   /// @param [in] gctx the geometry context for this building
+  /// @param mtvVector Vector of confined TrackingVolumes
   /// @param volumeMaterial dense material properties for this TrackingVolume
   /// @param rMin minimum radius
   /// @param rMax maximum radius
@@ -130,7 +134,7 @@ class CylinderVolumeHelper : public ITrackingVolumeHelper {
   ///
   /// @return shared pointer to a new TrackingVolume
   MutableTrackingVolumePtr createGapTrackingVolume(
-      const GeometryContext& gctx,
+      const GeometryContext& gctx, MutableTrackingVolumeVector& mtvVector,
       std::shared_ptr<const IVolumeMaterial> volumeMaterial, double rMin,
       double rMax, double zMin, double zMax, unsigned int materialLayers,
       bool cylinder = true,
@@ -139,6 +143,7 @@ class CylinderVolumeHelper : public ITrackingVolumeHelper {
   /// Create a gap volume from dimensions and
   ///
   /// @param [in] gctx the geometry context for this building
+  /// @param mtvVector Vector of confined TrackingVolumes
   /// @param volumeMaterial dense material properties for this TrackingVolume
   /// @param rMin minimum radius
   /// @param rMax maximum radius
@@ -151,7 +156,7 @@ class CylinderVolumeHelper : public ITrackingVolumeHelper {
   ///
   /// @return shared pointer to a new TrackingVolume
   MutableTrackingVolumePtr createGapTrackingVolume(
-      const GeometryContext& gctx,
+      const GeometryContext& gctx, MutableTrackingVolumeVector& mtvVector,
       std::shared_ptr<const IVolumeMaterial> volumeMaterial, double rMin,
       double rMax, double zMin, double zMax,
       const std::vector<double>& layerPositions, bool cylinder = true,
@@ -290,4 +295,4 @@ inline CylinderVolumeHelper::Config CylinderVolumeHelper::getConfiguration()
     const {
   return m_cfg;
 }
-}  // namespace Acts
\ No newline at end of file
+}  // namespace Acts
diff --git a/Core/include/Acts/Geometry/IConfinedTrackingVolumeBuilder.hpp b/Core/include/Acts/Geometry/IConfinedTrackingVolumeBuilder.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..bf7f5e0dee12760394823e86608659e5f6f56b17
--- /dev/null
+++ b/Core/include/Acts/Geometry/IConfinedTrackingVolumeBuilder.hpp
@@ -0,0 +1,37 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2016-2018 CERN for the benefit of the Acts project
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+///////////////////////////////////////////////////////////////////
+// ITrackingVolumeBuilder.h, Acts project
+///////////////////////////////////////////////////////////////////
+
+#pragma once
+#include <memory>
+#include <vector>
+
+namespace Acts {
+
+class TrackingVolume;
+using MutableTrackingVolumePtr = std::shared_ptr<TrackingVolume>;
+using MutableTrackingVolumeVector = std::vector<MutableTrackingVolumePtr>;
+
+/// @brief This is an interface class for constructing TrackingVolumes whose are
+/// confined in a mother-TrackingVolume
+class IConfinedTrackingVolumeBuilder {
+ public:
+  /// Virtual destructor
+  virtual ~IConfinedTrackingVolumeBuilder() = default;
+
+  /// Interface for constructing a vector of confined TrackingVolumes
+  virtual MutableTrackingVolumeVector centralVolumes() const = 0;
+
+  /// Interface for retreiving the identification string of the confined volumes
+  virtual const std::string& identification() const = 0;
+};
+
+}  // namespace Acts
\ No newline at end of file
diff --git a/Core/include/Acts/Geometry/ITrackingVolumeBuilder.hpp b/Core/include/Acts/Geometry/ITrackingVolumeBuilder.hpp
index df4bd5117a1832afa4573420af2572b9923dce38..1231d1886b1c00a26ebcdbf3aa3365ff6f002323 100644
--- a/Core/include/Acts/Geometry/ITrackingVolumeBuilder.hpp
+++ b/Core/include/Acts/Geometry/ITrackingVolumeBuilder.hpp
@@ -56,4 +56,4 @@ class ITrackingVolumeBuilder {
       VolumeBoundsPtr outsideBounds = nullptr) const = 0;
 };
 
-}  // namespace Acts
\ No newline at end of file
+}  // namespace Acts
diff --git a/Core/include/Acts/Geometry/ITrackingVolumeHelper.hpp b/Core/include/Acts/Geometry/ITrackingVolumeHelper.hpp
index 1d94d366cf9e782091eacb84ca912f8eec1b2cb2..874e07682cbd71429f83731558f4edb2af89dde3 100644
--- a/Core/include/Acts/Geometry/ITrackingVolumeHelper.hpp
+++ b/Core/include/Acts/Geometry/ITrackingVolumeHelper.hpp
@@ -32,6 +32,7 @@ using VolumeBoundsPtr = std::shared_ptr<const VolumeBounds>;
 
 using LayerVector = std::vector<LayerPtr>;
 using TrackingVolumeVector = std::vector<TrackingVolumePtr>;
+using MutableTrackingVolumeVector = std::vector<MutableTrackingVolumePtr>;
 
 ///  @class ITrackingVolumeHelper
 ///
@@ -56,6 +57,7 @@ class ITrackingVolumeHelper {
   /// together with the volume enevlope parameters
   /// @param volumeMaterial material properties for this TrackingVolume
   /// @param volumeBounds: confinement of this TrackingVolume
+  /// @param mtvVector (optional) Vector of confined TrackingVolumes
   /// @param transform (optional) placement of this TrackingVolume
   /// @param volumeName  volume name to be given
   /// @param btype (optional) BinningType - arbitrary(default) or equidistant
@@ -64,7 +66,7 @@ class ITrackingVolumeHelper {
   virtual MutableTrackingVolumePtr createTrackingVolume(
       const GeometryContext& gctx, const LayerVector& layers,
       std::shared_ptr<const IVolumeMaterial> volumeMaterial,
-      VolumeBoundsPtr volumeBounds,
+      VolumeBoundsPtr volumeBounds, MutableTrackingVolumeVector mtvVector = {},
       std::shared_ptr<const Transform3D> transform = nullptr,
       const std::string& volumeName = "UndefinedVolume",
       BinningType btype = arbitrary) const = 0;
@@ -76,6 +78,7 @@ class ITrackingVolumeHelper {
   /// if no bounds or HepTransform is given, they define the size
   /// together with the volume enevlope parameters
   /// @param volumeMaterial material properties for this TrackingVolume
+  /// @param mtvVector Vector of confined TrackingVolumes
   /// @param loc0Min, loc0Max, loc1Min, loc1Max : local position in space,
   /// this TrackingVolume is restricted to Translation only
   /// @param volumeName  volume name to be given
@@ -84,6 +87,7 @@ class ITrackingVolumeHelper {
   /// @return shared pointer to a new TrackingVolume
   virtual MutableTrackingVolumePtr createTrackingVolume(
       const GeometryContext& gctx, const LayerVector& layers,
+      MutableTrackingVolumeVector mtvVector,
       std::shared_ptr<const IVolumeMaterial> volumeMaterial, double loc0Min,
       double loc0Max, double loc1Min, double loc1Max,
       const std::string& volumeName = "UndefinedVolume",
@@ -92,6 +96,7 @@ class ITrackingVolumeHelper {
   /// Create a gap volume from dimensions and
   ///
   /// @param gctx is the geometry context for witch the volume is built
+  /// @param mtvVector Vector of confined TrackingVolumes
   /// @param volumeMaterial material properties for this TrackingVolume
   /// @param loc0Min, loc0Max, loc1Min, loc1Max : local position in space,
   /// this TrackingVolume is restricted to Translation only
@@ -101,7 +106,7 @@ class ITrackingVolumeHelper {
   ///
   /// @return shared pointer to a new TrackingVolume
   virtual MutableTrackingVolumePtr createGapTrackingVolume(
-      const GeometryContext& gctx,
+      const GeometryContext& gctx, MutableTrackingVolumeVector& mtvVector,
       std::shared_ptr<const IVolumeMaterial> volumeMaterial, double loc0Min,
       double loc0Max, double loc1Min, double loc1Max,
       unsigned int materialLayers, bool cylinder = true,
@@ -110,6 +115,7 @@ class ITrackingVolumeHelper {
   /// Create a gap volume from dimensions and
   ///
   /// @param gctx is the geometry context for witch the volume is built
+  /// @param mtvVector Vector of confined TrackingVolumes
   /// @param volumeMaterial material properties for this TrackingVolume
   /// @param loc0Min, loc0Max, loc1Min, loc1Max local position in space,
   /// @param layerPositions custom layer positions
@@ -119,7 +125,7 @@ class ITrackingVolumeHelper {
   ///
   /// @return shared pointer to a new TrackingVolume
   virtual MutableTrackingVolumePtr createGapTrackingVolume(
-      const GeometryContext& gctx,
+      const GeometryContext& gctx, MutableTrackingVolumeVector& mtvVector,
       std::shared_ptr<const IVolumeMaterial> volumeMaterial, double loc0Min,
       double loc0Max, double loc1Min, double loc1Max,
       const std::vector<double>& layerPositions, bool cylinder = true,
@@ -137,4 +143,4 @@ class ITrackingVolumeHelper {
       const TrackingVolumeVector& volumes) const = 0;
 };
 
-}  // namespace Acts
\ No newline at end of file
+}  // namespace Acts
diff --git a/Core/include/Acts/Geometry/TrackingVolume.hpp b/Core/include/Acts/Geometry/TrackingVolume.hpp
index c0a3c0888cae2609392a0e07dc4446ceb96399b8..7a011107f869e1128d785b4a72589a97f598c77b 100644
--- a/Core/include/Acts/Geometry/TrackingVolume.hpp
+++ b/Core/include/Acts/Geometry/TrackingVolume.hpp
@@ -45,6 +45,7 @@ using TrackingVolumeBoundaryPtr =
 // possible contained
 using TrackingVolumeArray = BinnedArray<TrackingVolumePtr>;
 using TrackingVolumeVector = std::vector<TrackingVolumePtr>;
+using MutableTrackingVolumeVector = std::vector<MutableTrackingVolumePtr>;
 using LayerArray = BinnedArray<LayerPtr>;
 using LayerVector = std::vector<LayerPtr>;
 
@@ -147,10 +148,12 @@ class TrackingVolume : public Volume {
       std::shared_ptr<const IVolumeMaterial> volumeMaterial,
       std::unique_ptr<const LayerArray> containedLayers = nullptr,
       std::shared_ptr<const TrackingVolumeArray> containedVolumes = nullptr,
+      MutableTrackingVolumeVector denseVolumes = {},
       const std::string& volumeName = "undefined") {
     return MutableTrackingVolumePtr(new TrackingVolume(
         std::move(htrans), std::move(volumeBounds), std::move(volumeMaterial),
-        std::move(containedLayers), std::move(containedVolumes), volumeName));
+        std::move(containedLayers), std::move(containedVolumes),
+        std::move(denseVolumes), volumeName));
   }
 
   /// Return the associated Layer to the global position
@@ -270,10 +273,12 @@ class TrackingVolume : public Volume {
   ///
   /// @param gctx The current geometry context object, e.g. alignment
   /// @param gp is the global position associated with that search
+  /// @param tol Search position tolerance for dense volumes
   ///
   /// @return plain pointer to associated with the position
   const TrackingVolume* lowestTrackingVolume(const GeometryContext& gctx,
-                                             const Vector3D& gp) const;
+                                             const Vector3D& gp,
+                                             const double tol = 0.) const;
 
   /// Return the confined static layer array - if it exists
   /// @return the BinnedArray of static layers if exists
@@ -282,6 +287,9 @@ class TrackingVolume : public Volume {
   /// Return the confined volumes of this container array - if it exists
   std::shared_ptr<const TrackingVolumeArray> confinedVolumes() const;
 
+  /// Return the confined dense volumes
+  const MutableTrackingVolumeVector denseVolumes() const;
+
   /// @brief Visit all sensitive surfaces
   ///
   /// @param visitor The callable. Will be called for each sensitive surface
@@ -333,8 +341,7 @@ class TrackingVolume : public Volume {
   /// @param neighbor is the TrackingVolume to be glued
   /// @param bsfNeighbor is the boudnary surface of the neighbor
   void glueTrackingVolume(const GeometryContext& gctx,
-                          BoundarySurfaceFace bsfMine,
-                          const MutableTrackingVolumePtr& neighbor,
+                          BoundarySurfaceFace bsfMine, TrackingVolume* neighbor,
                           BoundarySurfaceFace bsfNeighbor);
 
   /// Glue another tracking volume to this one
@@ -451,9 +458,13 @@ class TrackingVolume : public Volume {
       std::shared_ptr<const IVolumeMaterial> volumeMaterial,
       std::unique_ptr<const LayerArray> staticLayerArray = nullptr,
       std::shared_ptr<const TrackingVolumeArray> containedVolumeArray = nullptr,
+      MutableTrackingVolumeVector denseVolumeVector = {},
       const std::string& volumeName = "undefined");
 
  private:
+  void connectDenseBoundarySurfaces(
+      MutableTrackingVolumeVector& confinedDenseVolumes);
+
   /// Create Boundary Surface
   void createBoundarySurfaces();
 
@@ -499,6 +510,9 @@ class TrackingVolume : public Volume {
   /// Array of Volumes inside the Volume when actin as container
   std::shared_ptr<const TrackingVolumeArray> m_confinedVolumes = nullptr;
 
+  /// confined dense
+  MutableTrackingVolumeVector m_confinedDenseVolumes;
+
   /// Volumes to glue Volumes from the outside
   GlueVolumesDescriptor* m_glueVolumeDescriptor{nullptr};
 
@@ -508,7 +522,7 @@ class TrackingVolume : public Volume {
   /// The gometry type for the navigation schema
   GeometryType m_geometryType{NumberOfGeometryTypes};
 
-  //// Volume name for debug reasons & screen output
+  /// Volume name for debug reasons & screen output
   std::string m_name;
 
   /// color code for displaying
@@ -542,6 +556,10 @@ inline const LayerArray* TrackingVolume::confinedLayers() const {
   return m_confinedLayers.get();
 }
 
+inline const MutableTrackingVolumeVector TrackingVolume::denseVolumes() const {
+  return m_confinedDenseVolumes;
+}
+
 inline std::shared_ptr<const TrackingVolumeArray>
 TrackingVolume::confinedVolumes() const {
   return m_confinedVolumes;
@@ -577,4 +595,4 @@ inline bool TrackingVolume::hasBoundingVolumeHierarchy() const {
 
 #include "detail/TrackingVolume.ipp"
 
-}  // namespace Acts
+}  // namespace Acts
\ No newline at end of file
diff --git a/Core/include/Acts/Geometry/detail/TrackingVolume.ipp b/Core/include/Acts/Geometry/detail/TrackingVolume.ipp
index 6fd478351b8512583a6e3328452ec680fa1ba8e5..7cdd1437dd9f332e1293b78f7e0aedf7a4df85ff 100644
--- a/Core/include/Acts/Geometry/detail/TrackingVolume.ipp
+++ b/Core/include/Acts/Geometry/detail/TrackingVolume.ipp
@@ -102,6 +102,23 @@ std::vector<BoundaryIntersection> TrackingVolume::compatibleBoundaries(
     }
     nonExcludedBoundaries.push_back(bSurface);
   }
+
+  const std::vector<std::shared_ptr<TrackingVolume>> confinedDenseVolumes =
+      denseVolumes();
+  for (const auto& dv : confinedDenseVolumes) {
+    auto& bSurfacesConfined = dv->boundarySurfaces();
+    for (auto& bsIter : bSurfacesConfined) {
+      // get the boundary surface pointer
+      const BoundarySurfaceT<TrackingVolume>* bSurface = bsIter.get();
+      const auto& bSurfaceRep = bSurface->surfaceRepresentation();
+      // exclude the on boundary object
+      if (excludeObject && excludeObject == &bSurfaceRep) {
+        continue;
+      }
+      nonExcludedBoundaries.push_back(bSurface);
+    }
+  }
+
   return sorter(gctx, nonExcludedBoundaries, position, direction, options,
                 corrfnc);
 }
diff --git a/Core/include/Acts/Propagator/detail/ConstrainedStep.hpp b/Core/include/Acts/Propagator/detail/ConstrainedStep.hpp
index 8968912d85579b160667f6b7a6b6759250277814..ec66aa2a12591e24b06819c3754923bec751bc00 100644
--- a/Core/include/Acts/Propagator/detail/ConstrainedStep.hpp
+++ b/Core/include/Acts/Propagator/detail/ConstrainedStep.hpp
@@ -23,7 +23,7 @@ namespace detail {
 struct ConstrainedStep {
   /// the types of constraints
   /// from accuracy - this can vary up and down given a good step estimator
-  /// form actor    - this would be a typical navigation step
+  /// from actor    - this would be a typical navigation step
   /// from aborter  - this would be a target condition
   /// from user     - this is user given for what reason ever
   enum Type : int { accuracy = 0, actor = 1, aborter = 2, user = 3 };
diff --git a/Core/src/Geometry/CuboidVolumeBuilder.cpp b/Core/src/Geometry/CuboidVolumeBuilder.cpp
index 119b51137ae4abd0145465e15622bc0855caad9b..b0fcfe2aba3df58cc47ad878b581163435376c65 100644
--- a/Core/src/Geometry/CuboidVolumeBuilder.cpp
+++ b/Core/src/Geometry/CuboidVolumeBuilder.cpp
@@ -143,10 +143,23 @@ std::shared_ptr<Acts::TrackingVolume> Acts::CuboidVolumeBuilder::buildVolume(
       layArrCreator.layerArray(gctx, layVec, minMax.first, minMax.second,
                                BinningType::arbitrary, BinningValue::binX));
 
-  // Build TrackingVolume
-  auto trackVolume = TrackingVolume::create(
-      std::make_shared<const Transform3D>(trafo), bounds, cfg.volumeMaterial,
-      std::move(layArr), nullptr, cfg.name);
+  // Build confined volumes
+  if (cfg.trackingVolumes.empty())
+    for (VolumeConfig vc : cfg.volumeCfg)
+      cfg.trackingVolumes.push_back(buildVolume(gctx, vc));
+
+  std::shared_ptr<TrackingVolume> trackVolume;
+  if (layVec.empty()) {
+    // Build TrackingVolume
+    trackVolume = TrackingVolume::create(
+        std::make_shared<const Transform3D>(trafo), bounds, cfg.volumeMaterial,
+        nullptr, nullptr, cfg.trackingVolumes, cfg.name);
+  } else {
+    // Build TrackingVolume
+    trackVolume = TrackingVolume::create(
+        std::make_shared<const Transform3D>(trafo), bounds, cfg.volumeMaterial,
+        std::move(layArr), nullptr, cfg.trackingVolumes, cfg.name);
+  }
   trackVolume->sign(GeometrySignature::Global);
 
   return trackVolume;
@@ -165,10 +178,10 @@ Acts::MutableTrackingVolumePtr Acts::CuboidVolumeBuilder::trackingVolume(
   // Glue volumes
   for (unsigned int i = 0; i < volumes.size() - 1; i++) {
     volumes[i + 1]->glueTrackingVolume(
-        gctx, BoundarySurfaceFace::negativeFaceYZ, volumes[i],
+        gctx, BoundarySurfaceFace::negativeFaceYZ, volumes[i].get(),
         BoundarySurfaceFace::positiveFaceYZ);
     volumes[i]->glueTrackingVolume(gctx, BoundarySurfaceFace::positiveFaceYZ,
-                                   volumes[i + 1],
+                                   volumes[i + 1].get(),
                                    BoundarySurfaceFace::negativeFaceYZ);
   }
 
@@ -210,4 +223,4 @@ Acts::MutableTrackingVolumePtr Acts::CuboidVolumeBuilder::trackingVolume(
 
   mtvp->sign(GeometrySignature::Global);
   return mtvp;
-}
+}
\ No newline at end of file
diff --git a/Core/src/Geometry/CylinderVolumeBuilder.cpp b/Core/src/Geometry/CylinderVolumeBuilder.cpp
index d7198052aa6898d05b0ac68145a0e3f49ae540fb..790e202630a54e52102cc7b12017d5ff5e38280b 100644
--- a/Core/src/Geometry/CylinderVolumeBuilder.cpp
+++ b/Core/src/Geometry/CylinderVolumeBuilder.cpp
@@ -73,6 +73,13 @@ Acts::CylinderVolumeBuilder::trackingVolume(
     // the positive Layer
     positiveLayers = m_cfg.layerBuilder->positiveLayers(gctx);
   }
+
+  // Build the confined volumes
+  MutableTrackingVolumeVector centralVolumes;
+  if (m_cfg.ctVolumeBuilder) {
+    centralVolumes = m_cfg.ctVolumeBuilder->centralVolumes();
+  }
+
   // (0) PREP WORK ------------------------------------------------
   //
   // a) volume config of the existing volume
@@ -127,9 +134,9 @@ Acts::CylinderVolumeBuilder::trackingVolume(
 
   // Find out with Layer analysis
   // analyze the layers
-  wConfig.nVolumeConfig = analyzeLayers(gctx, negativeLayers);
-  wConfig.cVolumeConfig = analyzeLayers(gctx, centralLayers);
-  wConfig.pVolumeConfig = analyzeLayers(gctx, positiveLayers);
+  wConfig.nVolumeConfig = analyzeContent(gctx, negativeLayers, {});  // TODO
+  wConfig.cVolumeConfig = analyzeContent(gctx, centralLayers, centralVolumes);
+  wConfig.pVolumeConfig = analyzeContent(gctx, positiveLayers, {});  // TODO
 
   std::string layerConfiguration = "|";
   if (wConfig.nVolumeConfig) {
@@ -184,7 +191,8 @@ Acts::CylinderVolumeBuilder::trackingVolume(
   auto barrel =
       wConfig.cVolumeConfig
           ? tvHelper->createTrackingVolume(
-                gctx, wConfig.cVolumeConfig.layers, m_cfg.volumeMaterial,
+                gctx, wConfig.cVolumeConfig.layers,
+                wConfig.cVolumeConfig.volumes, m_cfg.volumeMaterial,
                 wConfig.cVolumeConfig.rMin, wConfig.cVolumeConfig.rMax,
                 wConfig.cVolumeConfig.zMin, wConfig.cVolumeConfig.zMax,
                 m_cfg.volumeName + "::Barrel")
@@ -194,7 +202,8 @@ Acts::CylinderVolumeBuilder::trackingVolume(
   auto nEndcap =
       wConfig.nVolumeConfig
           ? tvHelper->createTrackingVolume(
-                gctx, wConfig.nVolumeConfig.layers, m_cfg.volumeMaterial,
+                gctx, wConfig.nVolumeConfig.layers,
+                wConfig.cVolumeConfig.volumes, m_cfg.volumeMaterial,
                 wConfig.nVolumeConfig.rMin, wConfig.nVolumeConfig.rMax,
                 wConfig.nVolumeConfig.zMin, wConfig.nVolumeConfig.zMax,
                 m_cfg.volumeName + "::NegativeEndcap")
@@ -204,7 +213,8 @@ Acts::CylinderVolumeBuilder::trackingVolume(
   auto pEndcap =
       wConfig.pVolumeConfig
           ? tvHelper->createTrackingVolume(
-                gctx, wConfig.pVolumeConfig.layers, m_cfg.volumeMaterial,
+                gctx, wConfig.pVolumeConfig.layers,
+                wConfig.cVolumeConfig.volumes, m_cfg.volumeMaterial,
                 wConfig.pVolumeConfig.rMin, wConfig.pVolumeConfig.rMax,
                 wConfig.pVolumeConfig.zMin, wConfig.pVolumeConfig.zMax,
                 m_cfg.volumeName + "::PositiveEndcap")
@@ -283,9 +293,10 @@ Acts::CylinderVolumeBuilder::trackingVolume(
     if (wConfig.fGapVolumeConfig) {
       // create the gap volume
       auto fGap = tvHelper->createGapTrackingVolume(
-          gctx, m_cfg.volumeMaterial, wConfig.fGapVolumeConfig.rMin,
-          wConfig.fGapVolumeConfig.rMax, wConfig.fGapVolumeConfig.zMin,
-          wConfig.fGapVolumeConfig.zMax, 1, false, m_cfg.volumeName + "::fGap");
+          gctx, wConfig.cVolumeConfig.volumes, m_cfg.volumeMaterial,
+          wConfig.fGapVolumeConfig.rMin, wConfig.fGapVolumeConfig.rMax,
+          wConfig.fGapVolumeConfig.zMin, wConfig.fGapVolumeConfig.zMax, 1,
+          false, m_cfg.volumeName + "::fGap");
       // push it back into the list
       existingContainer.push_back(fGap);
     }
@@ -293,9 +304,10 @@ Acts::CylinderVolumeBuilder::trackingVolume(
     if (wConfig.sGapVolumeConfig) {
       // create the gap volume
       auto sGap = tvHelper->createGapTrackingVolume(
-          gctx, m_cfg.volumeMaterial, wConfig.sGapVolumeConfig.rMin,
-          wConfig.sGapVolumeConfig.rMax, wConfig.sGapVolumeConfig.zMin,
-          wConfig.sGapVolumeConfig.zMax, 1, false, m_cfg.volumeName + "::sGap");
+          gctx, wConfig.cVolumeConfig.volumes, m_cfg.volumeMaterial,
+          wConfig.sGapVolumeConfig.rMin, wConfig.sGapVolumeConfig.rMax,
+          wConfig.sGapVolumeConfig.zMin, wConfig.sGapVolumeConfig.zMax, 1,
+          false, m_cfg.volumeName + "::sGap");
       // push it back into the list
       existingContainer.push_back(sGap);
     }
@@ -354,14 +366,15 @@ Acts::CylinderVolumeBuilder::trackingVolume(
 }
 
 // -----------------------------
-Acts::VolumeConfig Acts::CylinderVolumeBuilder::analyzeLayers(
-    const GeometryContext& gctx, const LayerVector& lVector) const {
+Acts::VolumeConfig Acts::CylinderVolumeBuilder::analyzeContent(
+    const GeometryContext& gctx, const LayerVector& lVector,
+    const MutableTrackingVolumeVector& mtvVector) const {
   // @TODO add envelope tolerance
   //
   // return object
   VolumeConfig lConfig;
   // only if the vector is present it can actually be analyzed
-  if (!lVector.empty()) {
+  if (!lVector.empty() || !mtvVector.empty()) {
     // we have layers
     lConfig.present = true;
     // loop over the layer
@@ -402,9 +415,22 @@ Acts::VolumeConfig Acts::CylinderVolumeBuilder::analyzeLayers(
         //!< @todo check for Endcap Ring config
       }
     }
+    for (auto& volume : mtvVector) {
+      const CylinderVolumeBounds* cvBounds =
+          dynamic_cast<const CylinderVolumeBounds*>(&volume->volumeBounds());
+      if (cvBounds != nullptr) {
+        takeSmaller(lConfig.rMin, cvBounds->innerRadius());
+        takeBigger(lConfig.rMax, cvBounds->outerRadius());
+        takeSmaller(lConfig.zMin, -cvBounds->halflengthZ());
+        takeBigger(lConfig.zMax, cvBounds->halflengthZ());
+      }
+    }
   }
+
   // set the layers to the layer vector
   lConfig.layers = lVector;
+  // set the layers to the layer vector
+  lConfig.volumes = mtvVector;
   // overwrite to radius 0 if needed
   if (m_cfg.buildToRadiusZero) {
     ACTS_VERBOSE("This layer builder is configured to build to the beamline.");
@@ -413,4 +439,4 @@ Acts::VolumeConfig Acts::CylinderVolumeBuilder::analyzeLayers(
 
   // and return what you have
   return lConfig;
-}
+}
\ No newline at end of file
diff --git a/Core/src/Geometry/CylinderVolumeHelper.cpp b/Core/src/Geometry/CylinderVolumeHelper.cpp
index 94ed74d6a7f8fca99900f76c731ef412f21f2b40..3fd0ef80ed5303e75bcd7ee2124ebcf10c33e2fc 100644
--- a/Core/src/Geometry/CylinderVolumeHelper.cpp
+++ b/Core/src/Geometry/CylinderVolumeHelper.cpp
@@ -53,6 +53,7 @@ Acts::CylinderVolumeHelper::createTrackingVolume(
     const GeometryContext& gctx, const LayerVector& layers,
     std::shared_ptr<const IVolumeMaterial> volumeMaterial,
     std::shared_ptr<const VolumeBounds> volumeBounds,
+    MutableTrackingVolumeVector mtvVector,
     std::shared_ptr<const Transform3D> transform, const std::string& volumeName,
     BinningType bType) const {
   // the final one to build / sensitive Volume / Bounds
@@ -132,7 +133,8 @@ Acts::CylinderVolumeHelper::createTrackingVolume(
           : std::shared_ptr<const VolumeBounds>(cylinderBounds);
   // finally create the TrackingVolume
   tVolume = TrackingVolume::create(transform, volumeBoundsFinal, volumeMaterial,
-                                   std::move(layerArray), nullptr, volumeName);
+                                   std::move(layerArray), nullptr, mtvVector,
+                                   volumeName);
   // screen output
   ACTS_VERBOSE(
       "Created cylindrical volume at z-position :" << tVolume->center().z());
@@ -144,6 +146,7 @@ Acts::CylinderVolumeHelper::createTrackingVolume(
 std::shared_ptr<Acts::TrackingVolume>
 Acts::CylinderVolumeHelper::createTrackingVolume(
     const GeometryContext& gctx, const LayerVector& layers,
+    MutableTrackingVolumeVector mtvVector,
     std::shared_ptr<const IVolumeMaterial> volumeMaterial, double rMin,
     double rMax, double zMin, double zMax, const std::string& volumeName,
     BinningType bType) const {
@@ -179,13 +182,13 @@ Acts::CylinderVolumeHelper::createTrackingVolume(
                        : nullptr;
   // call to the creation method with Bounds & Translation3D
   return createTrackingVolume(gctx, layers, volumeMaterial,
-                              VolumeBoundsPtr(cBounds), transform, volumeName,
-                              bType);
+                              VolumeBoundsPtr(cBounds), mtvVector, transform,
+                              volumeName, bType);
 }
 
 std::shared_ptr<Acts::TrackingVolume>
 Acts::CylinderVolumeHelper::createGapTrackingVolume(
-    const GeometryContext& gctx,
+    const GeometryContext& gctx, MutableTrackingVolumeVector& mtvVector,
     std::shared_ptr<const IVolumeMaterial> volumeMaterial, double rMin,
     double rMax, double zMin, double zMax, unsigned int materialLayers,
     bool cylinder, const std::string& volumeName) const {
@@ -211,14 +214,14 @@ Acts::CylinderVolumeHelper::createGapTrackingVolume(
   }
 
   // now call the main method
-  return createGapTrackingVolume(gctx, volumeMaterial, rMin, rMax, zMin, zMax,
-                                 layerPositions, cylinder, volumeName,
-                                 arbitrary);
+  return createGapTrackingVolume(gctx, mtvVector, volumeMaterial, rMin, rMax,
+                                 zMin, zMax, layerPositions, cylinder,
+                                 volumeName, arbitrary);
 }
 
 std::shared_ptr<Acts::TrackingVolume>
 Acts::CylinderVolumeHelper::createGapTrackingVolume(
-    const GeometryContext& gctx,
+    const GeometryContext& gctx, MutableTrackingVolumeVector& mtvVector,
     std::shared_ptr<const IVolumeMaterial> volumeMaterial, double rMin,
     double rMax, double zMin, double zMax,
     const std::vector<double>& layerPositions, bool cylinder,
@@ -257,8 +260,8 @@ Acts::CylinderVolumeHelper::createGapTrackingVolume(
     }
   }
   // now call the createTrackingVolume() method
-  return createTrackingVolume(gctx, layers, volumeMaterial, rMin, rMax, zMin,
-                              zMax, volumeName, bType);
+  return createTrackingVolume(gctx, layers, mtvVector, volumeMaterial, rMin,
+                              rMax, zMin, zMax, volumeName, bType);
 }
 
 std::shared_ptr<Acts::TrackingVolume>
@@ -743,8 +746,8 @@ void Acts::CylinderVolumeHelper::glueTrackingVolumes(
                                       << glueVolTwo->volumeName() << " @ "
                                       << faceTwo << " ]");
     // one to one is easy
-    mutableGlueVolOne->glueTrackingVolume(gctx, faceOne, mutableGlueVolTwo,
-                                          faceTwo);
+    mutableGlueVolOne->glueTrackingVolume(gctx, faceOne,
+                                          mutableGlueVolTwo.get(), faceTwo);
 
   } else if (volOneGlueVols <= 1) {
     // (ii) one -> many
diff --git a/Core/src/Geometry/SurfaceArrayCreator.cpp b/Core/src/Geometry/SurfaceArrayCreator.cpp
index 471ca727ce305aa7ebea0239509d4a9411b588f0..7480106cd99bda47d30e5d2db083475ae18ec5b0 100644
--- a/Core/src/Geometry/SurfaceArrayCreator.cpp
+++ b/Core/src/Geometry/SurfaceArrayCreator.cpp
@@ -324,7 +324,6 @@ Acts::SurfaceArrayCreator::surfaceArrayOnPlane(
   ACTS_VERBOSE(" -- with " << surfaces.size() << " surfaces.")
   ACTS_VERBOSE(" -- with " << bins1 << " x " << bins2 << " = " << bins1 * bins2
                            << " bins.");
-
   // Transformation
   Transform3D transform =
       transformOpt != nullptr ? *transformOpt : Transform3D::Identity();
diff --git a/Core/src/Geometry/TrackingVolume.cpp b/Core/src/Geometry/TrackingVolume.cpp
index 61c3800e44c007ee86eae3f2adb3791fcfafb930..d8e8c2b96979bf9bc5addfbfbda1370edc13b99c 100644
--- a/Core/src/Geometry/TrackingVolume.cpp
+++ b/Core/src/Geometry/TrackingVolume.cpp
@@ -1,6 +1,6 @@
 // This file is part of the Acts project.
 //
-// Copyright (C) 2016-2018 CERN for the benefit of the Acts project
+// Copyright (C) 2016-2019 CERN for the benefit of the Acts project
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -47,14 +47,17 @@ Acts::TrackingVolume::TrackingVolume(
     std::shared_ptr<const IVolumeMaterial> volumeMaterial,
     std::unique_ptr<const LayerArray> staticLayerArray,
     std::shared_ptr<const TrackingVolumeArray> containedVolumeArray,
+    MutableTrackingVolumeVector denseVolumeVector,
     const std::string& volumeName)
     : Volume(std::move(htrans), std::move(volumeBounds)),
       m_volumeMaterial(std::move(volumeMaterial)),
       m_confinedLayers(std::move(staticLayerArray)),
       m_confinedVolumes(std::move(containedVolumeArray)),
+      m_confinedDenseVolumes({}),
       m_name(volumeName) {
   createBoundarySurfaces();
   interlinkLayers();
+  connectDenseBoundarySurfaces(denseVolumeVector);
 }
 
 // constructor for arguments
@@ -84,12 +87,19 @@ Acts::TrackingVolume::~TrackingVolume() {
 }
 
 const Acts::TrackingVolume* Acts::TrackingVolume::lowestTrackingVolume(
-    const GeometryContext& /*gctx*/, const Vector3D& gp) const {
+    const GeometryContext& /*gctx*/, const Vector3D& gp,
+    const double tol) const {
   // confined static volumes - highest hierarchy
   if (m_confinedVolumes) {
     return (m_confinedVolumes->object(gp).get());
   }
 
+  // search for dense volumes
+  if (!m_confinedDenseVolumes.empty())
+    for (auto& denseVolume : m_confinedDenseVolumes)
+      if (denseVolume->inside(gp, tol))
+        return denseVolume.get();
+
   // there is no lower sub structure
   return this;
 }
@@ -110,6 +120,15 @@ void Acts::TrackingVolume::sign(GeometrySignature geosign,
       mutableVolumesIter->sign(geosign, geotype);
     }
   }
+
+  // finally for confined dense volumes
+  if (!m_confinedDenseVolumes.empty()) {
+    for (auto& volumesIter : m_confinedDenseVolumes) {
+      auto mutableVolumesIter =
+          std::const_pointer_cast<TrackingVolume>(volumesIter);
+      mutableVolumesIter->sign(geosign, geotype);
+    }
+  }
 }
 
 const std::vector<
@@ -118,6 +137,47 @@ Acts::TrackingVolume::boundarySurfaces() const {
   return (m_boundarySurfaces);
 }
 
+void Acts::TrackingVolume::connectDenseBoundarySurfaces(
+    MutableTrackingVolumeVector& confinedDenseVolumes) {
+  if (!confinedDenseVolumes.empty()) {
+    BoundaryOrientation bo;
+    // Walk over each dense volume
+    for (auto& confDenseVol : confinedDenseVolumes) {
+      // Walk over each boundary surface of the volume
+      auto& boundSur = confDenseVol->boundarySurfaces();
+      for (unsigned int i = 0; i < boundSur.size(); i++) {
+        // Skip empty entries since we do not know the shape of the dense volume
+        // and therewith the used indices
+        if (boundSur.at(i) == nullptr) {
+          continue;
+        }
+
+        // Use mother volume as the opposite direction of the already used
+        // direction
+        auto mutableBs =
+            std::const_pointer_cast<BoundarySurfaceT<TrackingVolume>>(
+                boundSur.at(i));
+        if (mutableBs->m_insideVolume != nullptr &&
+            mutableBs->m_outsideVolume == nullptr) {
+          bo = BoundaryOrientation::outsideVolume;
+          mutableBs->attachVolume(this, bo);
+        } else {
+          if (mutableBs->m_insideVolume == nullptr &&
+              mutableBs->m_outsideVolume != nullptr) {
+            bo = BoundaryOrientation::insideVolume;
+            mutableBs->attachVolume(this, bo);
+          }
+        }
+
+        // Update the boundary
+        confDenseVol->updateBoundarySurface((BoundarySurfaceFace)i, mutableBs);
+      }
+      // Store the volume
+      m_confinedDenseVolumes.push_back(std::move(confDenseVol));
+    }
+  }
+}
+
 void Acts::TrackingVolume::createBoundarySurfaces() {
   // transform Surfaces To BoundarySurfaces
   std::vector<std::shared_ptr<const Surface>> surfaces =
@@ -143,10 +203,10 @@ void Acts::TrackingVolume::createBoundarySurfaces() {
   }
 }
 
-void Acts::TrackingVolume::glueTrackingVolume(
-    const GeometryContext& gctx, BoundarySurfaceFace bsfMine,
-    const std::shared_ptr<TrackingVolume>& neighbor,
-    BoundarySurfaceFace bsfNeighbor) {
+void Acts::TrackingVolume::glueTrackingVolume(const GeometryContext& gctx,
+                                              BoundarySurfaceFace bsfMine,
+                                              TrackingVolume* neighbor,
+                                              BoundarySurfaceFace bsfNeighbor) {
   // Find the connection of the two tracking volumes: binR returns the center
   // except for cylindrical volumes
   Vector3D bPosition(binningPosition(gctx, binR));
@@ -343,6 +403,7 @@ void Acts::TrackingVolume::closeGeometry(
     materialDecorator->decorate(*thisVolume);
   }
 
+  this->assignGeoID(volumeID);
   // loop over the boundary surfaces
   GeometryID::Value iboundary = 0;
   // loop over the boundary surfaces
@@ -397,6 +458,16 @@ void Acts::TrackingVolume::closeGeometry(
       auto mutableVolumesIter =
           std::const_pointer_cast<TrackingVolume>(volumesIter);
       mutableVolumesIter->closeGeometry(materialDecorator, volumeMap, vol);
+      mutableVolumesIter->setMotherVolume(this);
+    }
+  }
+
+  if (!m_confinedDenseVolumes.empty()) {
+    for (auto& volumesIter : m_confinedDenseVolumes) {
+      auto mutableVolumesIter =
+          std::const_pointer_cast<TrackingVolume>(volumesIter);
+      mutableVolumesIter->closeGeometry(materialDecorator, volumeMap, vol);
+      mutableVolumesIter->setMotherVolume(this);
     }
   }
 }
@@ -422,4 +493,4 @@ void Acts::TrackingVolume::visitSurfaces(
       volume->visitSurfaces(visitor);
     }
   }
-}
+}
\ No newline at end of file
diff --git a/Plugins/DD4hep/include/Acts/Plugins/DD4hep/ConvertDD4hepDetector.hpp b/Plugins/DD4hep/include/Acts/Plugins/DD4hep/ConvertDD4hepDetector.hpp
index f05bb9686f17a0034d6f37522ea94a613b8abf63..c120a301abf4f31b789571133fc8ba598ad394c5 100644
--- a/Plugins/DD4hep/include/Acts/Plugins/DD4hep/ConvertDD4hepDetector.hpp
+++ b/Plugins/DD4hep/include/Acts/Plugins/DD4hep/ConvertDD4hepDetector.hpp
@@ -172,4 +172,12 @@ void collectCompounds_dd4hep(dd4hep::DetElement& detElement,
 /// detElement
 void collectLayers_dd4hep(dd4hep::DetElement& detElement,
                           std::vector<dd4hep::DetElement>& layers);
-}  // namespace Acts
+
+/// Method internally used by convertDD4hepDetector
+/// @param [in] detElement the dd4hep::DetElement of the volume of which the
+/// volumes should be collected
+/// @param [out] volumes the DD4hep::DetElements of the volumes contained by
+/// detElement
+void collectVolumes_dd4hep(dd4hep::DetElement& detElement,
+                           std::vector<dd4hep::DetElement>& volumes);
+}  // namespace Acts
\ No newline at end of file
diff --git a/Plugins/DD4hep/include/Acts/Plugins/DD4hep/DD4hepVolumeBuilder.hpp b/Plugins/DD4hep/include/Acts/Plugins/DD4hep/DD4hepVolumeBuilder.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d25a200721d5175a99c3b7a15c2215545d1292b2
--- /dev/null
+++ b/Plugins/DD4hep/include/Acts/Plugins/DD4hep/DD4hepVolumeBuilder.hpp
@@ -0,0 +1,106 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2018 CERN for the benefit of the Acts project
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#pragma once
+#include "Acts/Geometry/IConfinedTrackingVolumeBuilder.hpp"
+#include "Acts/Geometry/TrackingVolume.hpp"
+#include "Acts/Surfaces/Surface.hpp"
+#include "Acts/Utilities/Definitions.hpp"
+#include "Acts/Utilities/Logger.hpp"
+
+class TrackingVolume;
+using MutableTrackingVolumePtr = std::shared_ptr<TrackingVolume>;
+using MutableTrackingVolumeVector = std::vector<MutableTrackingVolumePtr>;
+
+class TGeoMatrix;
+
+namespace dd4hep {
+class DetElement;
+}
+
+namespace Acts {
+
+/// @brief build confined TrackingVolumes of one cylinder setup from DD4hep
+/// input.
+///
+/// This class is an implementation of the Acts::IConfinedTrackingVolumeBuilder,
+/// creating the central (volumes of barrel), the negative and positive volumes
+/// (volumes of endcaps) of one hierarchy (e.g. ECal, HCal...) with input from
+/// DD4hep.
+
+class DD4hepVolumeBuilder : public IConfinedTrackingVolumeBuilder {
+ public:
+  /// @struct Config
+  /// Nested configuration struct for steering of the volume builder
+  struct Config {
+    /// string based identification
+    std::string configurationName = "undefined";
+    /// Vector of central confined volumes
+    std::vector<dd4hep::DetElement> centralVolumes;
+  };
+
+  /// Constructor
+  /// @param [in] config is the configuration struct
+  /// @param [in] logger is the logging instance
+  DD4hepVolumeBuilder(const Acts::DD4hepVolumeBuilder::Config& config,
+                      std::unique_ptr<const Logger> logger);
+
+  /// Destructor
+  ~DD4hepVolumeBuilder() override;
+
+  /// @brief Builder method for cylindrical, confined volume
+  ///
+  /// @return The vector of TrackingVolumes at the central sector
+  MutableTrackingVolumeVector centralVolumes() const final;
+
+  /// Name identification
+  /// @return The string based identification of this configuration
+  const std::string& identification() const final;
+
+  /// Set the configuration object
+  /// @param [in] Config is the configuration struct
+  void setConfiguration(const Config& config);
+
+  /// Get the configuration object
+  /// @return The used configuration struct
+  Config getConfiguration() const;
+
+  /// Set logging instance
+  /// @param [in] logger Logger in use
+  void setLogger(std::unique_ptr<const Logger> logger);
+
+ private:
+  /// Configruation object
+  Config m_cfg;
+
+  /// Logging instance
+  std::unique_ptr<const Logger> m_logger;
+
+  /// Private access to the logger
+  /// @return Used logger
+  const Logger& logger() const { return *m_logger; }
+
+  /// @brief Converter of the transformation of a volume from DD4hep to Acts
+  /// formalism
+  ///
+  /// @param [in] tGeoTrans Transformation of the DD4hep DetElement
+  /// @return Pointer to the corresponding Acts transformation
+  std::shared_ptr<const Acts::Transform3D> convertTransform(
+      const TGeoMatrix* tGeoTrans) const;
+};
+
+inline const std::string& DD4hepVolumeBuilder::identification() const {
+  return m_cfg.configurationName;
+}
+
+inline DD4hepVolumeBuilder::Config DD4hepVolumeBuilder::getConfiguration()
+    const {
+  return m_cfg;
+}
+
+}  // namespace Acts
\ No newline at end of file
diff --git a/Plugins/DD4hep/src/ConvertDD4hepDetector.cpp b/Plugins/DD4hep/src/ConvertDD4hepDetector.cpp
index f44d826a0cf012abb16ff234f4a98c4a7d25be98..867cddaaaae75330a1b7fb97daca4ecaf6bf84d7 100644
--- a/Plugins/DD4hep/src/ConvertDD4hepDetector.cpp
+++ b/Plugins/DD4hep/src/ConvertDD4hepDetector.cpp
@@ -24,6 +24,7 @@
 #include "Acts/Plugins/DD4hep/ActsExtension.hpp"
 #include "Acts/Plugins/DD4hep/ConvertDD4hepMaterial.hpp"
 #include "Acts/Plugins/DD4hep/DD4hepLayerBuilder.hpp"
+#include "Acts/Plugins/DD4hep/DD4hepVolumeBuilder.hpp"
 #include "Acts/Utilities/BinningData.hpp"
 #include "TGeoManager.h"
 
@@ -424,8 +425,9 @@ std::shared_ptr<const CylinderVolumeBuilder> volumeBuilder_dd4hep(
                  << subDetector.name()
                  << " is a (sensitive) Barrel volume - building barrel.");
     /// the dd4hep::DetElements of the layers of the central volume
-    std::vector<dd4hep::DetElement> centralLayers;
+    std::vector<dd4hep::DetElement> centralLayers, centralVolumes;
     collectLayers_dd4hep(subDetector, centralLayers);
+    collectVolumes_dd4hep(subDetector, centralVolumes);
 
     // configure SurfaceArrayCreator
     auto surfaceArrayCreator =
@@ -449,6 +451,16 @@ std::shared_ptr<const CylinderVolumeBuilder> volumeBuilder_dd4hep(
         Acts::getDefaultLogger(std::string("D2A_LB_") + subDetector.name(),
                                loggingLevel));
 
+    // Configure DD4hepVolumeBuilder
+    Acts::DD4hepVolumeBuilder::Config vbConfig;
+    vbConfig.configurationName = subDetector.name();
+    vbConfig.centralVolumes = centralVolumes;
+    auto dd4hepVolumeBuilder =
+        std::make_shared<const Acts::DD4hepVolumeBuilder>(
+            vbConfig,
+            Acts::getDefaultLogger(std::string("D2A_VB_") + subDetector.name(),
+                                   loggingLevel));
+
     // the configuration object of the volume builder
     Acts::CylinderVolumeBuilder::Config cvbConfig;
     // get the dimensions of the volume
@@ -475,6 +487,7 @@ std::shared_ptr<const CylinderVolumeBuilder> volumeBuilder_dd4hep(
     cvbConfig.volumeName = subDetector.name();
     cvbConfig.volumeMaterial = volumeMaterial;
     cvbConfig.layerBuilder = dd4hepLayerBuilder;
+    cvbConfig.ctVolumeBuilder = dd4hepVolumeBuilder;
     auto cylinderVolumeBuilder =
         std::make_shared<const Acts::CylinderVolumeBuilder>(
             cvbConfig,
@@ -583,4 +596,22 @@ void collectLayers_dd4hep(dd4hep::DetElement& detElement,
     collectLayers_dd4hep(childDetElement, layers);
   }
 }
-}  // End of namespace Acts
+
+void collectVolumes_dd4hep(dd4hep::DetElement& detElement,
+                           std::vector<dd4hep::DetElement>& volumes) {
+  const dd4hep::DetElement::Children& children = detElement.children();
+  for (auto& child : children) {
+    dd4hep::DetElement childDetElement = child.second;
+    Acts::ActsExtension* detExtension = nullptr;
+    try {
+      detExtension = childDetElement.extension<Acts::ActsExtension>();
+    } catch (std::runtime_error& e) {
+    }
+    if ((detExtension != nullptr) && detExtension->hasType("volume")) {
+      volumes.push_back(childDetElement);
+      continue;
+    }
+    collectVolumes_dd4hep(childDetElement, volumes);
+  }
+}
+}  // End of namespace Acts
\ No newline at end of file
diff --git a/Plugins/DD4hep/src/DD4hepVolumeBuilder.cpp b/Plugins/DD4hep/src/DD4hepVolumeBuilder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f522278646eb40779040de14e529767960af241f
--- /dev/null
+++ b/Plugins/DD4hep/src/DD4hepVolumeBuilder.cpp
@@ -0,0 +1,112 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2018 CERN for the benefit of the Acts project
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "Acts/Plugins/DD4hep/DD4hepVolumeBuilder.hpp"
+#include "Acts/Geometry/CylinderVolumeBounds.hpp"
+#include "Acts/Material/HomogeneousVolumeMaterial.hpp"
+#include "Acts/Plugins/DD4hep/DD4hepDetectorElement.hpp"
+#include "Acts/Plugins/TGeo/TGeoPrimitivesHelpers.hpp"
+#include "Acts/Surfaces/CylinderSurface.hpp"
+#include "Acts/Surfaces/RadialBounds.hpp"
+#include "Acts/Utilities/Units.hpp"
+#include "DD4hep/Detector.h"
+
+#include <boost/algorithm/string.hpp>
+
+Acts::DD4hepVolumeBuilder::DD4hepVolumeBuilder(
+    const Acts::DD4hepVolumeBuilder::Config& config,
+    std::unique_ptr<const Logger> logger)
+    : m_cfg(), m_logger(std::move(logger)) {
+  setConfiguration(config);
+}
+
+Acts::DD4hepVolumeBuilder::~DD4hepVolumeBuilder() = default;
+
+void Acts::DD4hepVolumeBuilder::setConfiguration(
+    const Acts::DD4hepVolumeBuilder::Config& config) {
+  m_cfg = config;
+}
+
+std::vector<std::shared_ptr<Acts::TrackingVolume>>
+Acts::DD4hepVolumeBuilder::centralVolumes() const {
+  if (m_cfg.centralVolumes.empty()) {
+    ACTS_VERBOSE("[L] No layers handed over for central volume!");
+    return {};
+  }
+
+  ACTS_VERBOSE(
+      "[L] Received layers for central volume -> creating "
+      "cylindrical layers");
+
+  // Resulting volumes
+  MutableTrackingVolumeVector volumes;
+  // Inner/outer radius and half length of the barrel
+  double rMin, rMax, dz;
+
+  // Go through volumes
+  for (auto& detElement : m_cfg.centralVolumes) {
+    // Access the global transformation matrix of the volume
+    auto transform =
+        convertTransform(&(detElement.nominal().worldTransformation()));
+    // Get the shape of the volume
+    TGeoShape* geoShape = detElement.placement().ptr()->GetVolume()->GetShape();
+
+    if (geoShape != nullptr) {
+      TGeoTubeSeg* tube = dynamic_cast<TGeoTubeSeg*>(geoShape);
+      if (tube == nullptr)
+        ACTS_ERROR(
+            "[L] Cylinder layer has wrong shape - needs to be TGeoTubeSeg!");
+
+      // Extract the boundaries
+      rMin = tube->GetRmin() * units::_cm;
+      rMax = tube->GetRmax() * units::_cm;
+      dz = tube->GetDz() * units::_cm;
+
+    } else {
+      throw std::logic_error(
+          std::string("Volume DetElement: ") + detElement.name() +
+          std::string(" has not a shape "
+                      "added to its extension. Please check your detector "
+                      "constructor!"));
+    }
+    // Build boundaries
+    CylinderVolumeBounds cvBounds(rMin, rMax, dz);
+    // Extract material if available
+    dd4hep::Material ddmaterial = detElement.volume().material();
+    if (!boost::iequals(ddmaterial.name(), "vacuum")) {
+      Material volumeMaterial(ddmaterial.radLength() * Acts::units::_cm,
+                              ddmaterial.intLength() * Acts::units::_cm,
+                              ddmaterial.A(), ddmaterial.Z(),
+                              ddmaterial.density() / pow(Acts::units::_cm, 3));
+
+      volumes.push_back(TrackingVolume::create(
+          transform, std::make_shared<const CylinderVolumeBounds>(cvBounds),
+          std::make_shared<const HomogeneousVolumeMaterial>(volumeMaterial)));
+    } else {
+      volumes.push_back(TrackingVolume::create(
+          transform, std::make_shared<const CylinderVolumeBounds>(cvBounds)));
+    }
+  }
+  return volumes;
+}
+
+std::shared_ptr<const Acts::Transform3D>
+Acts::DD4hepVolumeBuilder::convertTransform(const TGeoMatrix* tGeoTrans) const {
+  // Get the placement and orientation in respect to its mother
+  const Double_t* rotation = tGeoTrans->GetRotationMatrix();
+  const Double_t* translation = tGeoTrans->GetTranslation();
+  auto transform =
+      std::make_shared<const Transform3D>(TGeoPrimitivesHelpers::makeTransform(
+          Acts::Vector3D(rotation[0], rotation[3], rotation[6]),
+          Acts::Vector3D(rotation[1], rotation[4], rotation[7]),
+          Acts::Vector3D(rotation[2], rotation[5], rotation[8]),
+          Acts::Vector3D(translation[0] * units::_cm,
+                         translation[1] * units::_cm,
+                         translation[2] * units::_cm)));
+  return (transform);
+}
diff --git a/Plugins/TGeo/include/Acts/Plugins/TGeo/TGeoPrimitivesHelpers.hpp b/Plugins/TGeo/include/Acts/Plugins/TGeo/TGeoPrimitivesHelpers.hpp
index c0c01836ec3a34a0472e8edd28c6b7610bd1df17..b7fb7469bd563e3f2a90ca865b281146ec43a99f 100644
--- a/Plugins/TGeo/include/Acts/Plugins/TGeo/TGeoPrimitivesHelpers.hpp
+++ b/Plugins/TGeo/include/Acts/Plugins/TGeo/TGeoPrimitivesHelpers.hpp
@@ -14,10 +14,10 @@ namespace Acts {
 
 namespace TGeoPrimitivesHelpers {
 
-Transform3D makeTransform(const Eigen::Vector3d& rotationMatrixCol0,
-                          const Eigen::Vector3d& rotationMatrixCol1,
-                          const Eigen::Vector3d& rotationMatrixCol2,
-                          const Eigen::Vector3d& translation) {
+inline Transform3D makeTransform(const Eigen::Vector3d& rotationMatrixCol0,
+                                 const Eigen::Vector3d& rotationMatrixCol1,
+                                 const Eigen::Vector3d& rotationMatrixCol2,
+                                 const Eigen::Vector3d& translation) {
   Transform3D trf;
   trf.matrix().block(0, 0, 3, 1) = rotationMatrixCol0;
   trf.matrix().block(0, 1, 3, 1) = rotationMatrixCol1;
diff --git a/Tests/Core/CommonHelpers/include/Acts/Tests/CommonHelpers/CubicTrackingGeometry.hpp b/Tests/Core/CommonHelpers/include/Acts/Tests/CommonHelpers/CubicTrackingGeometry.hpp
index 66a37d89d42baf83e8a141cddb758fa09d20753d..3345b5cb0ad0f1fae6ea32720a565826d64a33a4 100644
--- a/Tests/Core/CommonHelpers/include/Acts/Tests/CommonHelpers/CubicTrackingGeometry.hpp
+++ b/Tests/Core/CommonHelpers/include/Acts/Tests/CommonHelpers/CubicTrackingGeometry.hpp
@@ -121,7 +121,7 @@ struct CubicTrackingGeometry {
 
     auto trackVolume1 = TrackingVolume::create(
         std::make_shared<const Transform3D>(trafoVol1), boundsVol, nullptr,
-        std::move(layArr1), nullptr, "Volume 1");
+        std::move(layArr1), nullptr, {}, "Volume 1");
     trackVolume1->sign(GeometrySignature::Global);
 
     // Build volume for surfaces with positive x-values
@@ -137,17 +137,17 @@ struct CubicTrackingGeometry {
 
     auto trackVolume2 = TrackingVolume::create(
         std::make_shared<const Transform3D>(trafoVol2), boundsVol, nullptr,
-        std::move(layArr2), nullptr, "Volume 2");
+        std::move(layArr2), nullptr, {}, "Volume 2");
 
     trackVolume2->sign(GeometrySignature::Global);
 
     // Glue volumes
     trackVolume2->glueTrackingVolume(
-        geoContext, BoundarySurfaceFace::negativeFaceYZ, trackVolume1,
+        geoContext, BoundarySurfaceFace::negativeFaceYZ, trackVolume1.get(),
         BoundarySurfaceFace::positiveFaceYZ);
 
     trackVolume1->glueTrackingVolume(
-        geoContext, BoundarySurfaceFace::positiveFaceYZ, trackVolume2,
+        geoContext, BoundarySurfaceFace::positiveFaceYZ, trackVolume2.get(),
         BoundarySurfaceFace::negativeFaceYZ);
 
     // Build world volume
@@ -190,4 +190,4 @@ struct CubicTrackingGeometry {
   std::reference_wrapper<const GeometryContext> geoContext;
 };
 }  // namespace Test
-}  // namespace Acts
+}  // namespace Acts
\ No newline at end of file
diff --git a/Tests/Core/CommonHelpers/include/Acts/Tests/CommonHelpers/CylindricalTrackingGeometry.hpp b/Tests/Core/CommonHelpers/include/Acts/Tests/CommonHelpers/CylindricalTrackingGeometry.hpp
index 065b046e738b37c9570f27c4d3d7bdc27ef1abfa..0b0b5a5de6a9e26676aafb04a3d1f1e758d98e6c 100644
--- a/Tests/Core/CommonHelpers/include/Acts/Tests/CommonHelpers/CylindricalTrackingGeometry.hpp
+++ b/Tests/Core/CommonHelpers/include/Acts/Tests/CommonHelpers/CylindricalTrackingGeometry.hpp
@@ -230,7 +230,7 @@ struct CylindricalTrackingGeometry {
         std::make_shared<const CylinderVolumeBounds>(25., 300., 1100.);
     // create the Tracking volume
     auto pVolume = TrackingVolume::create(nullptr, pVolumeBounds, nullptr,
-                                          std::move(pLayerArray), nullptr,
+                                          std::move(pLayerArray), nullptr, {},
                                           "Pixel::Barrel");
 
     // The combined volume
diff --git a/Tests/Core/Geometry/CuboidVolumeBuilderTests.cpp b/Tests/Core/Geometry/CuboidVolumeBuilderTests.cpp
index 1bca5116fac2f7f9f5a3c01e65abe11f3770adac..9d1ba6caddafae27cddc30b8c23cefc2a56bd36f 100644
--- a/Tests/Core/Geometry/CuboidVolumeBuilderTests.cpp
+++ b/Tests/Core/Geometry/CuboidVolumeBuilderTests.cpp
@@ -16,11 +16,14 @@
 
 #include "Acts/Geometry/TrackingGeometry.hpp"
 #include "Acts/Geometry/TrackingVolume.hpp"
+#include "Acts/Propagator/Navigator.hpp"
 #include "Acts/Geometry/Layer.hpp"
 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
 #include "Acts/Material/HomogeneousVolumeMaterial.hpp"
 #include "Acts/Material/Material.hpp"
 #include "Acts/Material/MaterialProperties.hpp"
+#include "Acts/Propagator/Propagator.hpp"
+#include "Acts/Propagator/StraightLineStepper.hpp"
 #include "Acts/Surfaces/RectangleBounds.hpp"
 #include "Acts/Tests/CommonHelpers/DetectorElementStub.hpp"
 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
@@ -28,12 +31,34 @@
 #include "Acts/Geometry/TrackingGeometryBuilder.hpp"
 #include "Acts/Utilities/Definitions.hpp"
 #include "Acts/Utilities/Units.hpp"
+#include "Acts/Material/HomogeneousVolumeMaterial.hpp"
 
 using namespace Acts::UnitLiterals;
 
 namespace Acts {
 namespace Test {
 
+struct StepVolumeCollector {
+  ///
+  /// @brief Data container for result analysis
+  ///
+  struct this_result {
+    // Position of the propagator after each step
+    std::vector<Vector3D> position;
+    // Volume of the propagator after each step
+    std::vector<TrackingVolume const*> volume;
+  };
+
+  using result_type = this_result;
+
+  template <typename propagator_state_t, typename stepper_t>
+  void operator()(propagator_state_t& state, const stepper_t& stepper,
+                  result_type& result) const {
+    result.position.push_back(stepper.position(state.stepping));
+    result.volume.push_back(state.navigation.currentVolume);
+  }
+};
+
 BOOST_AUTO_TEST_CASE(CuboidVolumeBuilderTest) {
   // Construct builder
   CuboidVolumeBuilder cvb;
@@ -233,5 +258,216 @@ BOOST_AUTO_TEST_CASE(CuboidVolumeBuilderTest) {
           ->volumeName(),
       volumeConfig2.name);
 }
+
+BOOST_AUTO_TEST_CASE(CuboidVolumeBuilderTest_confinedVolumes) {
+  // Production factory
+  CuboidVolumeBuilder cvb;
+
+  // Create a test context
+  GeometryContext tgContext = GeometryContext();
+  MagneticFieldContext mfContext = MagneticFieldContext();
+
+  // Build a volume that confines another volume
+  CuboidVolumeBuilder::VolumeConfig vCfg;
+  vCfg.position = {1. * units::_m, 0., 0.};
+  vCfg.length = {2. * units::_m, 1. * units::_m, 1. * units::_m};
+  vCfg.name = "Test volume";
+  // Build and add 2 confined volumes
+  CuboidVolumeBuilder::VolumeConfig cvCfg1;
+  cvCfg1.position = {1.1 * units::_m, 0., 0.};
+  cvCfg1.length = {10. * units::_cm, 10. * units::_cm, 10. * units::_cm};
+  cvCfg1.name = "Confined volume1";
+  cvCfg1.volumeMaterial =
+      std::shared_ptr<const IVolumeMaterial>(new HomogeneousVolumeMaterial(
+          Material(352.8, 407., 9.012, 4., 1.848e-3)));
+  CuboidVolumeBuilder::VolumeConfig cvCfg2;
+  cvCfg2.position = {0.9 * units::_m, 0., 0.};
+  cvCfg2.length = {10. * units::_cm, 10. * units::_cm, 10. * units::_cm};
+  cvCfg2.name = "Confined volume2";
+  vCfg.volumeCfg = {cvCfg1, cvCfg2};
+
+  // Build detector
+  CuboidVolumeBuilder::Config config;
+  config.position = {1. * units::_m, 0., 0.};
+  config.length = {2. * units::_m, 1. * units::_m, 1. * units::_m};
+  config.volumeCfg = {vCfg};
+
+  cvb.setConfig(config);
+  TrackingGeometryBuilder::Config tgbCfg;
+  tgbCfg.trackingVolumeBuilders.push_back(
+      [=](const auto& context, const auto& inner, const auto& vb) {
+        return cvb.trackingVolume(context, inner, vb);
+      });
+  TrackingGeometryBuilder tgb(tgbCfg);
+  std::shared_ptr<const TrackingGeometry> detector =
+      tgb.trackingGeometry(tgContext);
+
+  // Test that the right volume is selected
+  BOOST_TEST(detector->lowestTrackingVolume(tgContext, {1. * units::_m, 0., 0.})
+                 ->volumeName() == vCfg.name);
+  BOOST_TEST(
+      detector->lowestTrackingVolume(tgContext, {1.1 * units::_m, 0., 0.})
+          ->volumeName() == cvCfg1.name);
+  BOOST_TEST(
+      detector->lowestTrackingVolume(tgContext, {0.9 * units::_m, 0., 0.})
+          ->volumeName() == cvCfg2.name);
+
+  // Set propagator and navigator
+  PropagatorOptions<ActionList<StepVolumeCollector>> propOpts(tgContext,
+                                                              mfContext);
+  propOpts.maxStepSize = 10. * units::_mm;
+  StraightLineStepper sls;
+  Navigator navi(detector);
+  navi.resolvePassive = true;
+  navi.resolveMaterial = true;
+  navi.resolveSensitive = true;
+
+  Propagator<StraightLineStepper, Navigator> prop(sls, navi);
+
+  // Set initial parameters for the particle track
+  Vector3D startParams(0., 0., 0.), startMom(1. * units::_GeV, 0., 0.);
+  SingleCurvilinearTrackParameters<ChargedPolicy> sbtp(
+      std::nullopt, startParams, startMom, 1., 0.);
+
+  // Launch and collect results
+  const auto& result = prop.propagate(sbtp, propOpts).value();
+  const StepVolumeCollector::this_result& stepResult =
+      result.get<typename StepVolumeCollector::result_type>();
+
+  // Check the identified volumes
+  for (unsigned int i = 0; i < stepResult.position.size(); i++) {
+    if (i > 0) {
+      BOOST_TEST(stepResult.position[i].x() > 0.);
+    }
+    if (stepResult.position[i].x() >= 0.85 * units::_m &&
+        stepResult.position[i].x() < 0.95 * units::_m) {
+      BOOST_TEST(stepResult.volume[i]->volumeName() == cvCfg2.name);
+      BOOST_TEST(stepResult.volume[i]->volumeMaterial() == nullptr);
+    } else {
+      if (stepResult.position[i].x() >= 1.05 * units::_m &&
+          stepResult.position[i].x() < 1.15 * units::_m) {
+        BOOST_TEST(stepResult.volume[i]->volumeName() == cvCfg1.name);
+        BOOST_TEST(stepResult.volume[i]->volumeMaterial() != nullptr);
+      } else {
+        if (stepResult.position[i].x() < 2. * units::_m) {
+          BOOST_TEST(stepResult.volume[i]->volumeName() == vCfg.name);
+          BOOST_TEST(stepResult.volume[i]->volumeMaterial() == nullptr);
+        }
+      }
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE(CuboidVolumeBuilderTest_confinedVolumes_edgecases) {
+  // Production factory
+  CuboidVolumeBuilder cvb;
+
+  // Create a test context
+  GeometryContext tgContext = GeometryContext();
+  MagneticFieldContext mfContext = MagneticFieldContext();
+
+  // Build a volume that confines another volume
+  CuboidVolumeBuilder::VolumeConfig vCfg1;
+  vCfg1.position = {1. * units::_m, 0., 0.};
+  vCfg1.length = {2. * units::_m, 1. * units::_m, 1. * units::_m};
+  vCfg1.name = "Test volume1";
+  // Build and add 4 confined volumes
+  // Volume that is missed and quite orthogonal to the starting position
+  CuboidVolumeBuilder::VolumeConfig cvCfg1;
+  cvCfg1.position = {0.1 * units::_m, 0.4 * units::_m, 0.4 * units::_m};
+  cvCfg1.length = {10. * units::_cm, 10. * units::_cm, 10. * units::_cm};
+  cvCfg1.name = "Confined volume1";
+  cvCfg1.volumeMaterial =
+      std::shared_ptr<const IVolumeMaterial>(new HomogeneousVolumeMaterial(
+          Material(352.8, 407., 9.012, 4., 1.848e-3)));
+  // Volume that is missed but far away such that it may be hit
+  CuboidVolumeBuilder::VolumeConfig cvCfg2;
+  cvCfg2.position = {1.9 * units::_m, -0.4 * units::_m, -0.4 * units::_m};
+  cvCfg2.length = {10. * units::_cm, 10. * units::_cm, 10. * units::_cm};
+  cvCfg2.name = "Confined volume2";
+  // Volume that is hit but with identical boundary as its mother
+  // TODO: Moved slightly inside the volume since otherwise the navigation
+  // breaks due to overlapping boundary surfaces. The corresponding test below
+  // is changed accordingly.
+  CuboidVolumeBuilder::VolumeConfig cvCfg3;
+  cvCfg3.position = {1.9 * units::_m, 0., 0.};
+  cvCfg3.length = {10. * units::_cm, 10. * units::_cm, 10. * units::_cm};
+  cvCfg3.name = "Confined volume3";
+  // Volume to grind along the boundary
+  CuboidVolumeBuilder::VolumeConfig cvCfg4;
+  cvCfg4.position = {1. * units::_m, 5. * units::_cm, 0.};
+  cvCfg4.length = {10. * units::_cm, 10. * units::_cm, 10. * units::_cm};
+  cvCfg4.name = "Confined volume4";
+  vCfg1.volumeCfg = {cvCfg1, cvCfg2, cvCfg3, cvCfg4};
+
+  // Build a volume that confines another volume
+  CuboidVolumeBuilder::VolumeConfig vCfg2;
+  vCfg2.position = {2.5 * units::_m, 0., 0.};
+  vCfg2.length = {1. * units::_m, 1. * units::_m, 1. * units::_m};
+  vCfg2.name = "Test volume2";
+
+  // Build detector
+  CuboidVolumeBuilder::Config config;
+  config.position = {1.5 * units::_m, 0., 0.};
+  config.length = {3. * units::_m, 1. * units::_m, 1. * units::_m};
+  config.volumeCfg = {vCfg1, vCfg2};
+
+  cvb.setConfig(config);
+  TrackingGeometryBuilder::Config tgbCfg;
+  tgbCfg.trackingVolumeBuilders.push_back(
+      [=](const auto& context, const auto& inner, const auto& vb) {
+        return cvb.trackingVolume(context, inner, vb);
+      });
+  TrackingGeometryBuilder tgb(tgbCfg);
+  std::shared_ptr<const TrackingGeometry> detector =
+      tgb.trackingGeometry(tgContext);
+
+  // Set propagator and navigator
+  PropagatorOptions<ActionList<StepVolumeCollector>> propOpts(tgContext,
+                                                              mfContext);
+  propOpts.maxStepSize = 10. * units::_mm;
+  StraightLineStepper sls;
+  Navigator navi(detector);
+  navi.resolvePassive = true;
+  navi.resolveMaterial = true;
+  navi.resolveSensitive = true;
+
+  Propagator<StraightLineStepper, Navigator> prop(sls, navi);
+
+  // Set initial parameters for the particle track
+  Vector3D startParams(0., 0., 0.), startMom(1. * units::_GeV, 0., 0.);
+  SingleCurvilinearTrackParameters<ChargedPolicy> sbtp(
+      std::nullopt, startParams, startMom, 1., 0.);
+
+  // Launch and collect results
+  const auto& result = prop.propagate(sbtp, propOpts).value();
+  const StepVolumeCollector::this_result& stepResult =
+      result.get<typename StepVolumeCollector::result_type>();
+
+  for (unsigned int i = 0; i < stepResult.position.size(); i++) {
+    // Check the movement in the right direction
+    if (i > 0) {
+      BOOST_TEST(stepResult.position[i].x() > 0.);
+    }
+    // Check the identified volumes
+    if (stepResult.position[i].x() >= 0.95 * units::_m &&
+        stepResult.position[i].x() < 1.05 * units::_m) {
+      BOOST_TEST(stepResult.volume[i]->volumeName() == cvCfg4.name);
+    } else {
+      if (stepResult.position[i].x() >= 1.85 * units::_m &&
+          stepResult.position[i].x() < 1.95 * units::_m) {
+        BOOST_TEST(stepResult.volume[i]->volumeName() == cvCfg3.name);
+      } else {
+        if (stepResult.position[i].x() < 2. * units::_m) {
+          BOOST_TEST(stepResult.volume[i]->volumeName() == vCfg1.name);
+        } else {
+          if (stepResult.position[i].x() < 3. * units::_m) {
+            BOOST_TEST(stepResult.volume[i]->volumeName() == vCfg2.name);
+          }
+        }
+      }
+    }
+  }
+}
 }  // namespace Test
-}  // namespace Acts
+}  // namespace Acts
\ No newline at end of file
diff --git a/Tests/Core/Geometry/TrackingVolumeCreation.hpp b/Tests/Core/Geometry/TrackingVolumeCreation.hpp
index c38327ebe3f07adedb605b665b0a4463bd4c5932..06a76eff553473bc4f13e2a5ecc3cac2daeb4cdd 100644
--- a/Tests/Core/Geometry/TrackingVolumeCreation.hpp
+++ b/Tests/Core/Geometry/TrackingVolumeCreation.hpp
@@ -78,7 +78,7 @@ TrackingVolumePtr constructCylinderVolume(
       innerVolumeR, outerVolumeR, bUmax + volumeEnvelope);
 
   TrackingVolumePtr volume = TrackingVolume::create(
-      nullptr, volumeBounds, nullptr, std::move(layerArray), nullptr, name);
+      nullptr, volumeBounds, nullptr, std::move(layerArray), nullptr, {}, name);
   ///  return the volume
   return volume;
 }
diff --git a/Tests/Core/Propagator/StepperTests.cpp b/Tests/Core/Propagator/StepperTests.cpp
index 0d59bb0227595f2d7d7a4ba3d2fe2087ff142a09..bb278160b3dee54e09c26e8475d100a407ee6260 100644
--- a/Tests/Core/Propagator/StepperTests.cpp
+++ b/Tests/Core/Propagator/StepperTests.cpp
@@ -15,6 +15,7 @@
 #include <fstream>
 
 #include "Acts/Geometry/TrackingGeometry.hpp"
+#include "Acts/Propagator/MaterialInteractor.hpp"
 #include "Acts/Propagator/Navigator.hpp"
 #include "Acts/MagneticField/ConstantBField.hpp"
 #include "Acts/Material/HomogeneousVolumeMaterial.hpp"
@@ -29,6 +30,10 @@
 #include "Acts/Utilities/Definitions.hpp"
 #include "Acts/Geometry/GeometryContext.hpp"
 #include "Acts/MagneticField/MagneticFieldContext.hpp"
+#include "Acts/Surfaces/RectangleBounds.hpp"
+#include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
+#include "Acts/Material/ISurfaceMaterial.hpp"
+#include "Acts/Material/IVolumeMaterial.hpp"
 
 namespace tt = boost::test_tools;
 using namespace Acts::UnitLiterals;
@@ -545,6 +550,19 @@ BOOST_AUTO_TEST_CASE(step_extension_vacmatvac_test) {
   CHECK_CLOSE_ABS(endParams.first, endParamsControl.first, 1_um);
   CHECK_CLOSE_ABS(endParams.second, endParamsControl.second, 1_um);
 
+  BOOST_TEST(endParams.first.x() == endParamsControl.first.x(),
+             tt::tolerance(1e-5));
+  BOOST_TEST(endParams.first.y() == endParamsControl.first.y(),
+             tt::tolerance(1e-5));
+  BOOST_TEST(endParams.first.z() == endParamsControl.first.z(),
+             tt::tolerance(1e-5));
+  BOOST_TEST(endParams.second.x() == endParamsControl.second.x(),
+             tt::tolerance(1e-5));
+  BOOST_TEST(endParams.second.y() == endParamsControl.second.y(),
+             tt::tolerance(1e-5));
+  BOOST_TEST(endParams.second.z() == endParamsControl.second.z(),
+             tt::tolerance(1e-5));
+
   // Build launcher through material
   // Set initial parameters for the particle track by using the result of the
   // first volume
@@ -598,5 +616,158 @@ BOOST_AUTO_TEST_CASE(step_extension_vacmatvac_test) {
   CHECK_CLOSE_ABS(endParams.first, endParamsControl.first, 1_um);
   CHECK_CLOSE_ABS(endParams.second, endParamsControl.second, 1_um);
 }
+
+// Test case a). The DenseEnvironmentExtension should state that it is not
+// valid in this case.
+BOOST_AUTO_TEST_CASE(step_extension_trackercalomdt_test) {
+  double rotationAngle = M_PI * 0.5;
+  Vector3D xPos(cos(rotationAngle), 0., sin(rotationAngle));
+  Vector3D yPos(0., 1., 0.);
+  Vector3D zPos(-sin(rotationAngle), 0., cos(rotationAngle));
+  MaterialProperties matProp(352.8, 407., 9.012, 4., 1.848e-3, 0.5_mm);
+
+  CuboidVolumeBuilder cvb;
+  CuboidVolumeBuilder::SurfaceConfig sConf1;
+  sConf1.position = Vector3D(0.3_m, 0., 0.);
+  sConf1.rotation.col(0) = xPos;
+  sConf1.rotation.col(1) = yPos;
+  sConf1.rotation.col(2) = zPos;
+  sConf1.rBounds =
+      std::make_shared<const RectangleBounds>(RectangleBounds(0.5_m, 0.5_m));
+  sConf1.surMat = std::shared_ptr<const ISurfaceMaterial>(
+      new HomogeneousSurfaceMaterial(matProp));
+  sConf1.thickness = 1._mm;
+  CuboidVolumeBuilder::LayerConfig lConf1;
+  lConf1.surfaceCfg = sConf1;
+
+  CuboidVolumeBuilder::SurfaceConfig sConf2;
+  sConf2.position = Vector3D(0.6_m, 0., 0.);
+  sConf2.rotation.col(0) = xPos;
+  sConf2.rotation.col(1) = yPos;
+  sConf2.rotation.col(2) = zPos;
+  sConf2.rBounds =
+      std::make_shared<const RectangleBounds>(RectangleBounds(0.5_m, 0.5_m));
+  sConf2.surMat = std::shared_ptr<const ISurfaceMaterial>(
+      new HomogeneousSurfaceMaterial(matProp));
+  sConf2.thickness = 1._mm;
+  CuboidVolumeBuilder::LayerConfig lConf2;
+  lConf2.surfaceCfg = sConf2;
+
+  CuboidVolumeBuilder::VolumeConfig muConf1;
+  muConf1.position = {2.3_m, 0., 0.};
+  muConf1.length = {20._cm, 20._cm, 20._cm};
+  muConf1.volumeMaterial =
+      std::shared_ptr<const IVolumeMaterial>(new HomogeneousVolumeMaterial(
+          Material(352.8, 407., 9.012, 4., 1.848e-3)));
+  muConf1.name = "MDT1";
+  CuboidVolumeBuilder::VolumeConfig muConf2;
+  muConf2.position = {2.7_m, 0., 0.};
+  muConf2.length = {20._cm, 20._cm, 20._cm};
+  muConf2.volumeMaterial =
+      std::shared_ptr<const IVolumeMaterial>(new HomogeneousVolumeMaterial(
+          Material(352.8, 407., 9.012, 4., 1.848e-3)));
+  muConf2.name = "MDT2";
+
+  CuboidVolumeBuilder::VolumeConfig vConf1;
+  vConf1.position = {0.5_m, 0., 0.};
+  vConf1.length = {1._m, 1._m, 1._m};
+  vConf1.layerCfg = {lConf1, lConf2};
+  vConf1.name = "Tracker";
+  CuboidVolumeBuilder::VolumeConfig vConf2;
+  vConf2.position = {1.5_m, 0., 0.};
+  vConf2.length = {1._m, 1._m, 1._m};
+  vConf2.volumeMaterial =
+      std::shared_ptr<const IVolumeMaterial>(new HomogeneousVolumeMaterial(
+          Material(352.8, 407., 9.012, 4., 1.848e-3)));
+  vConf2.name = "Calorimeter";
+  CuboidVolumeBuilder::VolumeConfig vConf3;
+  vConf3.position = {2.5_m, 0., 0.};
+  vConf3.length = {1._m, 1._m, 1._m};
+  vConf3.volumeCfg = {muConf1, muConf2};
+  vConf3.name = "Muon system";
+  CuboidVolumeBuilder::Config conf;
+  conf.volumeCfg = {vConf1, vConf2, vConf3};
+  conf.position = {1.5_m, 0., 0.};
+  conf.length = {3._m, 1._m, 1._m};
+
+  // Build detector
+  cvb.setConfig(conf);
+  TrackingGeometryBuilder::Config tgbCfg;
+  tgbCfg.trackingVolumeBuilders.push_back(
+      [=](const auto& context, const auto& inner, const auto& vb) {
+        return cvb.trackingVolume(context, inner, vb);
+      });
+  TrackingGeometryBuilder tgb(tgbCfg);
+  std::shared_ptr<const TrackingGeometry> detector =
+      tgb.trackingGeometry(tgContext);
+
+  // Build navigator
+  Navigator naviVac(detector);
+  naviVac.resolvePassive = true;
+  naviVac.resolveMaterial = true;
+  naviVac.resolveSensitive = true;
+
+  // Set initial parameters for the particle track
+  Covariance cov = Covariance::Identity();
+  Vector3D startParams(0., 0., 0.), startMom(1._GeV, 0., 0.);
+  SingleCurvilinearTrackParameters<ChargedPolicy> sbtp(cov, startParams,
+                                                       startMom, 1., 0.);
+
+  // Set options for propagator
+  DenseStepperPropagatorOptions<ActionList<StepCollector, MaterialInteractor>,
+                                AbortList<EndOfWorld>>
+      propOpts(tgContext, mfContext);
+  propOpts.abortList.get<EndOfWorld>().maxX = 3._m;
+
+  // Build stepper and propagator
+  ConstantBField bField(Vector3D(0., 0., 0.));
+  EigenStepper<
+      ConstantBField, VoidIntersectionCorrector,
+      StepperExtensionList<DefaultExtension, DenseEnvironmentExtension>,
+      detail::HighestValidAuctioneer>
+      es(bField);
+  Propagator<EigenStepper<ConstantBField, VoidIntersectionCorrector,
+                          StepperExtensionList<DefaultExtension,
+                                               DenseEnvironmentExtension>,
+                          detail::HighestValidAuctioneer>,
+             Navigator>
+      prop(es, naviVac);
+
+  // Launch and collect results
+  const auto& result = prop.propagate(sbtp, propOpts).value();
+  const StepCollector::this_result& stepResult =
+      result.get<typename StepCollector::result_type>();
+
+  // Test that momentum changes only occured at the right detector parts
+  double lastMomentum = stepResult.momentum[0].x();
+  for (unsigned int i = 0; i < stepResult.position.size(); i++) {
+    // Test for changes
+    if ((stepResult.position[i].x() > 0.3_m &&
+         stepResult.position[i].x() < 0.6_m) ||
+        (stepResult.position[i].x() > 0.6_m &&
+         stepResult.position[i].x() <= 1._m) ||
+        (stepResult.position[i].x() > 1._m &&
+         stepResult.position[i].x() <= 2._m) ||
+        (stepResult.position[i].x() > 2.2_m &&
+         stepResult.position[i].x() <= 2.4_m) ||
+        (stepResult.position[i].x() > 2.6_m &&
+         stepResult.position[i].x() <= 2.8_m)) {
+      BOOST_TEST(stepResult.momentum[i].x() <= lastMomentum);
+      lastMomentum = stepResult.momentum[i].x();
+    } else
+    // Test the absence of momentum loss
+    {
+      if (stepResult.position[i].x() < 0.3_m ||
+          (stepResult.position[i].x() > 2._m &&
+           stepResult.position[i].x() <= 2.2_m) ||
+          (stepResult.position[i].x() > 2.4_m &&
+           stepResult.position[i].x() <= 2.6_m) ||
+          (stepResult.position[i].x() > 2.8_m &&
+           stepResult.position[i].x() <= 3._m)) {
+        BOOST_TEST(stepResult.momentum[i].x() == lastMomentum);
+      }
+    }
+  }
+}
 }  // namespace Test
-}  // namespace Acts
+}  // namespace Acts
\ No newline at end of file