diff --git a/corsika/detail/media/MediumPropertyModel.inl b/corsika/detail/media/MediumPropertyModel.inl
new file mode 100644
index 0000000000000000000000000000000000000000..3e584252b2675ce7f4cea2545b574b8c71b4d75a
--- /dev/null
+++ b/corsika/detail/media/MediumPropertyModel.inl
@@ -0,0 +1,31 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/media/IMediumPropertyModel.hpp>
+
+namespace corsika {
+
+  template <typename T>
+  template <typename... Args>
+  MediumPropertyModel<T>::MediumPropertyModel(Medium const medium, Args&&... args)
+      : T(std::forward<Args>(args)...)
+      , medium_(medium) {}
+
+  template <typename T>
+  Medium MediumPropertyModel<T>::getMedium(Point const&) const final override {
+    return medium_;
+  }
+
+  template <typename T>
+  void MediumPropertyModel<T>::setMedium(Medium const medium) {
+    medium_ = medium;
+  }
+
+} // namespace corsika
diff --git a/corsika/media/IMediumModel.hpp b/corsika/media/IMediumModel.hpp
index 538657cb6952a27ce4ff9e0d1ae89ac4ba8ab1fb..c63819251185b766d8da8869275fc91f00834c51 100644
--- a/corsika/media/IMediumModel.hpp
+++ b/corsika/media/IMediumModel.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -8,30 +8,29 @@
 
 #pragma once
 
-#include <corsika/framework/core/PhysicalUnits.hpp>
+#include <corsika/media/NuclearComposition.hpp>
 #include <corsika/framework/geometry/Line.hpp>
 #include <corsika/framework/geometry/Point.hpp>
 #include <corsika/framework/geometry/Trajectory.hpp>
-#include <corsika/media/NuclearComposition.hpp>
+#include <corsika/framework/core/PhysicalUnits.hpp>
 
 namespace corsika {
 
   class IMediumModel {
-
   public:
     virtual ~IMediumModel() = default; // LCOV_EXCL_LINE
 
-    virtual MassDensityType GetMassDensity(Point const&) const = 0;
+    virtual units::si::MassDensityType getMassDensity(Point const&) const = 0;
 
     // todo: think about the mixin inheritance of the trajectory vs the BaseTrajectory
     // approach; for now, only lines are supported
-    virtual GrammageType IntegratedGrammage(Trajectory<Line> const&,
-                                            LengthType) const = 0;
+    virtual units::si::GrammageType integratedGrammage(
+        Trajectory<Line> const&, units::si::LengthType) const = 0;
 
-    virtual LengthType ArclengthFromGrammage(Trajectory<Line> const&,
-                                             GrammageType) const = 0;
+    virtual units::si::LengthType arclengthFromGrammage(
+        Trajectory<Line> const&, units::si::GrammageType) const = 0;
 
-    virtual NuclearComposition const& GetNuclearComposition() const = 0;
+    virtual NuclearComposition const& getNuclearComposition() const = 0;
   };
 
 } // namespace corsika
diff --git a/corsika/media/IMediumPropertyModel.hpp b/corsika/media/IMediumPropertyModel.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4455a6242be0ecf5a5098ed19da7685879597565
--- /dev/null
+++ b/corsika/media/IMediumPropertyModel.hpp
@@ -0,0 +1,43 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/media/MediumProperties.hpp>
+
+#include <corsika/framework/geometry/Point.hpp>
+#include <corsika/framework/core/PhysicalUnits.hpp>
+
+namespace corsika {
+
+  /**
+   * An interface for type of media, needed e.g. to determine energy losses
+   *
+   * This is the base interface for media types.
+   *
+   */
+  template <typename TModel>
+  class IMediumPropertyModel : public TModel {
+
+  public:
+    /**
+     * Evaluate the medium type at a given location.
+     *
+     * @param  point    The location to evaluate at.
+     * @returns    The media type
+     */
+    virtual Medium getMedium(Point const&) const = 0;
+
+    /**
+     * A virtual default destructor.
+     */
+    virtual ~IMediumPropertyModel() = default;
+
+  }; // END: class IMediumTypeModel
+
+} // namespace corsika
diff --git a/corsika/media/MediumPropertyModel.hpp b/corsika/media/MediumPropertyModel.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..bf47b951496177e7da01cee7de4b744a2427fed8
--- /dev/null
+++ b/corsika/media/MediumPropertyModel.hpp
@@ -0,0 +1,53 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/media/IMediumPropertyModel.hpp>
+
+namespace corsika {
+
+  /**
+   * A model for the energy loss property of a medium.
+   *
+   */
+  template <typename T>
+  class MediumPropertyModel : public T {
+
+    Medium medium_; ///< The medium that is used for this medium.
+
+  public:
+    /**
+     * Construct a MediumPropertyModel.
+     *
+     * @param field    The refractive index to return everywhere.
+     */
+    template <typename... Args>
+    MediumPropertyModel(Medium const medium, Args&&... args);
+
+    /**
+     * Evaluate the medium type at a given location.
+     *
+     * @param  point    The location to evaluate at.
+     * @returns    The medium type as enum environment::Medium
+     */
+    Medium getMedium(Point const&) const override;
+
+    /**
+     * Set the medium type.
+     *
+     * @param  medium    The medium to store.
+     * @returns    The medium type as enum environment::Medium
+     */
+    void setMedium(Medium const medium) override;
+
+  }; // END: class MediumPropertyModel
+
+} // namespace corsika
+
+#include <corsika/detail/media/MediumPropertyModel.inl>
diff --git a/tests/media/testMedium.cpp b/tests/media/testMedium.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d963c5d1ed6a1351ff700aca5202d235b5ea0065
--- /dev/null
+++ b/tests/media/testMedium.cpp
@@ -0,0 +1,87 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#include <corsika/framework/core/PhysicalUnits.hpp>
+#include <corsika/framework/geometry/Line.hpp>
+#include <corsika/framework/geometry/RootCoordinateSystem.hpp>
+#include <corsika/framework/geometry/Vector.hpp>
+#include <corsika/media/FlatExponential.hpp>
+#include <corsika/media/HomogeneousMedium.hpp>
+#include <corsika/media/IMediumModel.hpp>
+#include <corsika/media/InhomogeneousMedium.hpp>
+#include <corsika/media/NuclearComposition.hpp>
+#include <corsika/media/MediumPropertyModel.hpp>
+
+#include <catch2/catch.hpp>
+
+using namespace corsika;
+using namespace corsika::units::si;
+
+TEST_CASE("MediumPropertyModel w/ Homogeneous") {
+
+  CoordinateSystem const& gCS =
+      RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
+
+  Point const gOrigin(gCS, {0_m, 0_m, 0_m});
+
+  // setup our interface types
+  using IModelInterface = IMediumPropertyModel<IMediumModel>;
+  using AtmModel = MediumPropertyModel<HomogeneousMedium<IModelInterface>>;
+
+  // the constant density
+  const auto density{19.2_g / cube(1_cm)};
+
+  // the composition we use for the homogenous medium
+  NuclearComposition const protonComposition(std::vector<Code>{Code::Proton},
+                                             std::vector<float>{1.f});
+
+  // the refrative index that we use
+  const Medium type = Medium::AirDry1Atm;
+
+  // create the atmospheric model
+  AtmModel medium(type, density, protonComposition);
+
+  // and require that it is constant
+  CHECK(type == medium.medium(Point(gCS, -10_m, 4_m, 35_km)));
+  CHECK(type == medium.medium(Point(gCS, +210_m, 0_m, 7_km)));
+  CHECK(type == medium.medium(Point(gCS, 0_m, 0_m, 0_km)));
+  CHECK(type == medium.medium(Point(gCS, 100_km, 400_km, 350_km)));
+
+  // a new refractive index
+  const Medium type2 = Medium::StandardRock;
+
+  // update the refractive index of this atmospheric model
+  medium.set_medium(type2);
+
+  // check that the returned refractive index is correct
+  CHECK(type2 == medium.medium(Point(gCS, -10_m, 4_m, 35_km)));
+  CHECK(type2 == medium.medium(Point(gCS, +210_m, 0_m, 7_km)));
+  CHECK(type2 == medium.medium(Point(gCS, 0_m, 0_m, 0_km)));
+  CHECK(type2 == medium.medium(Point(gCS, 100_km, 400_km, 350_km)));
+
+  // define our axis vector
+  Vector const axis(gCS, QuantityVector<dimensionless_d>(0, 0, 1));
+
+  // check the density and nuclear composition
+  CHECK(density == medium.GetMassDensity(Point(gCS, 0_m, 0_m, 0_m)));
+  medium.GetNuclearComposition();
+
+  // create a line of length 1 m
+  Line const line(gOrigin, Vector<SpeedType::dimension_type>(
+                               gCS, {1_m / second, 0_m / second, 0_m / second}));
+
+  // the end time of our line
+  auto const tEnd = 1_s;
+
+  // and the associated trajectory
+  Trajectory<Line> const trajectory(line, tEnd);
+
+  // and check the integrated grammage
+  CHECK((medium.IntegratedGrammage(trajectory, 3_m) / (density * 3_m)) == Approx(1));
+  CHECK((medium.ArclengthFromGrammage(trajectory, density * 5_m) / 5_m) == Approx(1));
+}