diff --git a/dumux/material/fluidsystems/3pimmiscible.hh b/dumux/material/fluidsystems/3pimmiscible.hh
new file mode 100644
index 0000000000000000000000000000000000000000..500a94be62e271fc853827e3acca3dd87e0782da
--- /dev/null
+++ b/dumux/material/fluidsystems/3pimmiscible.hh
@@ -0,0 +1,564 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 2 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \ingroup Fluidsystems
+ * \brief @copybrief Dumux::FluidSystems::ThreePImmiscible
+ */
+#ifndef DUMUX_3P_IMMISCIBLE_FLUID_SYSTEM_HH
+#define DUMUX_3P_IMMISCIBLE_FLUID_SYSTEM_HH
+
+#include <limits>
+#include <cassert>
+
+#include <dune/common/exceptions.hh>
+
+#include <dumux/material/fluidsystems/1pliquid.hh>
+#include <dumux/material/fluidsystems/1pgas.hh>
+#include <dumux/material/fluidstates/immiscible.hh>
+
+namespace Dumux {
+namespace FluidSystems {
+
+/*!
+ * \ingroup Fluidsystems
+ * \brief A fluid system for three-phase models assuming immiscibility and
+ *        thermodynamic equilibrium
+ *
+ * The fluid phases are completely specified by means of their
+ * constituting components.
+ * The wetting and the non-wetting phase can be defined individually
+ * via FluidSystem::OnePLiquid<Scalar, Component>. The gas phase can be defined via
+ * FluidSystems::OnePGas<Scalar, Component>
+ * These phases consist of one pure component.
+ *
+ * \tparam Scalar the scalar type
+ * \tparam WettingFluid the wetting phase fluid system (use FluidSystem::OnePLiquid<Scalar, Component>)
+ * \tparam NonwettingFluid the wetting phase fluid system (use FluidSystem::OnePLiquid<Scalar, Component>)
+ * \tparam Gas the gas phase fluid system (use FluidSystem::OnePGas<Scalar, Component>)
+ */
+template <class Scalar, class WettingFluid, class NonwettingFluid, class Gas>
+class ThreePImmiscible
+: public BaseFluidSystem<Scalar, ThreePImmiscible<Scalar, WettingFluid, NonwettingFluid, Gas> >
+{
+    static_assert((WettingFluid::numPhases == 1), "WettingFluid has more than one phase");
+    static_assert((NonwettingFluid::numPhases == 1), "NonwettingFluid has more than one phase");
+    static_assert((Gas::numPhases == 1), "Gas has more than one phase");
+    static_assert((WettingFluid::numComponents == 1), "WettingFluid has more than one component");
+    static_assert((NonwettingFluid::numComponents == 1), "NonwettingFluid has more than one component");
+    static_assert((Gas::numComponents == 1), "Gas has more than one component");
+
+    using ThisType = ThreePImmiscible<Scalar, WettingFluid, NonwettingFluid, Gas>;
+    using Base = BaseFluidSystem<Scalar, ThisType>;
+public:
+    /****************************************
+     * Fluid phase related static parameters
+     ****************************************/
+
+    //! Number of phases in the fluid system
+    static constexpr int numPhases = 3;
+
+    //! Index of the wetting phase
+    static constexpr int wPhaseIdx = 0;
+    //! Index of the non-wetting phase
+    static constexpr int nPhaseIdx = 1;
+    //! Index of the gas phase
+    static constexpr int gPhaseIdx = 2;
+
+    /*!
+     * \brief Return the human readable name of a fluid phase
+     * \param phaseIdx The index of the fluid phase to consider
+     */
+    static std::string phaseName(int phaseIdx)
+    {
+        assert(0 <= phaseIdx && phaseIdx < numPhases);
+
+        static std::string name[] = {
+            std::string("w"),
+            std::string("n"),
+            std::string("g")
+        };
+        return name[phaseIdx];
+    }
+
+    /*!
+     * \brief Return whether a phase is liquid
+     * \param phaseIdx The index of the fluid phase to consider
+     */
+    static bool isLiquid(int phaseIdx)
+    {
+        assert(0 <= phaseIdx && phaseIdx < numPhases);
+
+        switch(phaseIdx)
+        {
+            case wPhaseIdx: return WettingFluid::isLiquid(); break;
+            case nPhaseIdx: return NonwettingFluid::isLiquid(); break;
+            case gPhaseIdx: return Gas::isLiquid(); break;
+            default: DUNE_THROW(Dune::InvalidStateException, "Invalid phase index");
+        }
+    }
+
+    /*!
+     * \brief Returns true if and only if a fluid phase is assumed to
+     *        be an ideal mixture.
+     * \param phaseIdx The index of the fluid phase to consider
+     *
+     * We define an ideal mixture as a fluid phase where the fugacity
+     * coefficients of all components times the pressure of the phase
+     * are independent on the fluid composition. This assumption is true
+     * if immiscibility is assumed. If you are unsure what
+     * this function should return, it is safe to return false. The
+     * only damage done will be (slightly) increased computation times
+     * in some cases.
+     */
+    static bool isIdealMixture(int phaseIdx)
+    {
+        assert(0 <= phaseIdx && phaseIdx < numPhases);
+
+        // we assume immisibility
+        return true;
+    }
+
+    /*!
+     * \brief Returns true if and only if a fluid phase is assumed to
+     *        be compressible.
+     *
+     * Compressible means. that the partial derivative of the density
+     * to the fluid pressure is always larger than zero.
+     *
+     * \param phaseIdx The index of the fluid phase to consider
+     */
+    static constexpr bool isCompressible(int phaseIdx)
+    {
+        assert(0 <= phaseIdx && phaseIdx < numPhases);
+
+        // let the fluids decide
+        switch(phaseIdx)
+        {
+            case wPhaseIdx: return WettingFluid::isCompressible(); break;
+            case nPhaseIdx: return NonwettingFluid::isCompressible(); break;
+            case gPhaseIdx: return Gas::isCompressible(); break;
+            default: DUNE_THROW(Dune::InvalidStateException, "Invalid phase index");
+        }
+    }
+
+    /*!
+     * \brief Returns true if and only if a fluid phase is assumed to
+     *        be an ideal gas.
+     *
+     * \param phaseIdx The index of the fluid phase to consider
+     */
+    static bool isIdealGas(int phaseIdx)
+    {
+        assert(0 <= phaseIdx && phaseIdx < numPhases);
+
+        // let the fluids decide
+        switch(phaseIdx)
+        {
+            case wPhaseIdx: return WettingFluid::isIdealGas(); break;
+            case nPhaseIdx: return NonwettingFluid::isIdealGas(); break;
+            case gPhaseIdx: return Gas::isIdealGas(); break;
+            default: DUNE_THROW(Dune::InvalidStateException, "Invalid phase index");
+        }
+    }
+
+    /****************************************
+     * Component related static parameters
+     ****************************************/
+
+    //! Number of components in the fluid system
+    static constexpr int numComponents = 3;//WettingFluid::numComponents + NonwettingFluid::numComponents + Gas::numComponents; // TODO: 3??
+
+    //! Index of the wetting phase's component
+    static constexpr int wCompIdx = 0;
+    //! Index of the non-wetting phase's component
+    static constexpr int nCompIdx = 1;
+    //! Index of the gas phase's component
+    static constexpr int gCompIdx = 2; // TODO: correct??
+
+    /*!
+     * \brief Return the human readable name of a component
+     *
+     * \param compIdx index of the component
+     */
+    static std::string componentName(int compIdx)
+    {
+        assert(0 <= compIdx && compIdx < numComponents);
+
+        switch(compIdx)
+        {
+            case wCompIdx: return WettingFluid::name(); break;
+            case nCompIdx: return NonwettingFluid::name(); break;
+            case gCompIdx: return Gas::name(); break;
+            default: DUNE_THROW(Dune::InvalidStateException, "Invalid component index");
+        }
+    }
+
+    /*!
+     * \brief Return the molar mass of a component in \f$\mathrm{[kg/mol]}\f$.
+     * \param compIdx index of the component
+     */
+    static Scalar molarMass(int compIdx)
+    {
+        assert(0 <= compIdx && compIdx < numComponents);
+
+        switch(compIdx)
+        {
+            case wCompIdx: return WettingFluid::molarMass(); break;
+            case nCompIdx: return NonwettingFluid::molarMass(); break;
+            case gCompIdx: return Gas::molarMass(); break;
+            default: DUNE_THROW(Dune::InvalidStateException, "Invalid component index");
+        }
+    }
+
+    /*!
+     * \brief Critical temperature of a component \f$\mathrm{[K]}\f$.
+     * \param compIdx index of the component
+     */
+    static Scalar criticalTemperature(int compIdx)
+    {
+        assert(0 <= compIdx && compIdx < numComponents);
+
+        switch(compIdx)
+        {
+            case wCompIdx: return WettingFluid::criticalTemperature(); break;
+            case nCompIdx: return NonwettingFluid::criticalTemperature(); break;
+            case gCompIdx: return Gas::criticalTemperature(); break;
+            default: DUNE_THROW(Dune::InvalidStateException, "Invalid component index");
+        }
+    }
+
+    /*!
+     * \brief Critical pressure of a component \f$\mathrm{[Pa]}\f$.
+     * \param compIdx index of the component
+     */
+    static Scalar criticalPressure(int compIdx)
+    {
+        assert(0 <= compIdx && compIdx < numComponents);
+
+        switch(compIdx)
+        {
+            case wCompIdx: return WettingFluid::criticalPressure(); break;
+            case nCompIdx: return NonwettingFluid::criticalPressure(); break;
+            case gCompIdx: return Gas::criticalPressure(); break;
+            default: DUNE_THROW(Dune::InvalidStateException, "Invalid component index");
+        }
+    }
+
+    /*!
+     * \brief The acentric factor of a component \f$\mathrm{[-]}\f$.
+     * \param compIdx index of the component
+     */
+    static Scalar acentricFactor(int compIdx)
+    {
+        assert(0 <= compIdx && compIdx < numComponents);
+
+        switch(compIdx)
+        {
+            case wCompIdx: return WettingFluid::Component::acentricFactor(); break;
+            case nCompIdx: return NonwettingFluid::Component::acentricFactor(); break;
+            case gCompIdx: return Gas::Component::acentricFactor(); break;
+            default: DUNE_THROW(Dune::InvalidStateException, "Invalid component index");
+        }
+    }
+
+    /****************************************
+     * thermodynamic relations
+     ****************************************/
+
+    /*!
+     * \brief Initialize the fluid system's static parameters
+     */
+    static void init()
+    {
+        // two gaseous phases at once do not make sense physically!
+        // (But two liquids are fine)
+        assert(WettingFluid::isLiquid() && NonwettingFluid::isLiquid() && !Gas::isLiquid());
+    }
+
+    /*!
+     * \brief Initialize the fluid system's static parameters using
+     *        problem specific temperature and pressure ranges
+     *
+     * \param tempMin The minimum temperature used for tabulation of water \f$\mathrm{[K]}\f$
+     * \param tempMax The maximum temperature used for tabulation of water \f$\mathrm{[K]}\f$
+     * \param nTemp The number of ticks on the temperature axis of the  table of water
+     * \param pressMin The minimum pressure used for tabulation of water \f$\mathrm{[Pa]}\f$
+     * \param pressMax The maximum pressure used for tabulation of water \f$\mathrm{[Pa]}\f$
+     * \param nPress The number of ticks on the pressure axis of the  table of water
+     */
+    static void init(Scalar tempMin, Scalar tempMax, unsigned nTemp,
+                     Scalar pressMin, Scalar pressMax, unsigned nPress)
+    {
+        // two gaseous phases at once do not make sense physically!
+        assert(WettingFluid::isLiquid() && NonwettingFluid::isLiquid() && !Gas::isLiquid());
+
+        if(WettingFluid::Component::isTabulated)
+        {
+            std::cout << "Initializing tables for the wetting fluid properties ("
+                      << nTemp*nPress
+                      << " entries).\n";
+
+            WettingFluid::Component::init(tempMin, tempMax, nTemp,
+                                          pressMin, pressMax, nPress);
+
+        }
+
+        if(NonwettingFluid::Component::isTabulated)
+        {
+            std::cout << "Initializing tables for the non-wetting fluid properties ("
+                      << nTemp*nPress
+                      << " entries).\n";
+
+            NonwettingFluid::Component::init(tempMin, tempMax, nTemp,
+                                             pressMin, pressMax, nPress);
+
+        }
+
+        if(Gas::Component::isTabulated)
+        {
+            std::cout << "Initializing tables for the gas fluid properties ("
+                      << nTemp*nPress
+                      << " entries).\n";
+
+            Gas::Component::init(tempMin, tempMax, nTemp,
+                                 pressMin, pressMax, nPress);
+
+        }
+    }
+
+    using Base::density;
+    /*!
+     * \brief Calculate the density \f$\mathrm{[kg/m^3]}\f$ of a fluid phase
+     *
+     */
+    template <class FluidState>
+    static Scalar density(const FluidState &fluidState,
+                          int phaseIdx)
+    {
+        assert(0 <= phaseIdx && phaseIdx < numPhases);
+
+        Scalar temperature = fluidState.temperature(phaseIdx);
+        Scalar pressure = fluidState.pressure(phaseIdx);
+
+        switch(phaseIdx)
+        {
+            case wPhaseIdx: return WettingFluid::density(temperature, pressure); break;
+            case nPhaseIdx: return NonwettingFluid::density(temperature, pressure); break;
+            case gPhaseIdx: return Gas::density(temperature, pressure); break;
+            default: DUNE_THROW(Dune::InvalidStateException, "Invalid phase index");
+        }
+    }
+
+    using Base::viscosity;
+    /*!
+     * \brief Return the viscosity of a phase \f$\mathrm{[Pa*s]}\f$.
+     * \param fluidState The fluid state of the two-phase model
+     * \param phaseIdx Index of the fluid phase
+     */
+    template <class FluidState>
+    static Scalar viscosity(const FluidState &fluidState,
+                            int phaseIdx)
+    {
+        assert(0 <= phaseIdx  && phaseIdx < numPhases);
+
+        Scalar temperature = fluidState.temperature(phaseIdx);
+        Scalar pressure = fluidState.pressure(phaseIdx);
+
+        switch(phaseIdx)
+        {
+            case wPhaseIdx: return WettingFluid::viscosity(temperature, pressure); break;
+            case nPhaseIdx: return NonwettingFluid::viscosity(temperature, pressure); break;
+            case gPhaseIdx: return Gas::viscosity(temperature, pressure); break;
+            default: DUNE_THROW(Dune::InvalidStateException, "Invalid phase index");
+        }
+    }
+
+    using Base::fugacityCoefficient;
+    /*!
+     * \brief Calculate the fugacity coefficient \f$\mathrm{[-]}\f$ of an individual
+     *        component in a fluid phase
+     *
+     * The fugacity coefficient \f$\mathrm{\phi^\kappa_\alpha}\f$ is connected to the
+     * fugacity \f$\mathrm{f^\kappa_\alpha}\f$ and the component's mole
+     * fraction \f$\mathrm{x^\kappa_\alpha}\f$ by means of the relation
+     *
+     * \f[
+     f^\kappa_\alpha = \phi^\kappa_\alpha\;x^\kappa_\alpha\;p_\alpha
+     * \f]
+     *
+     * \param fluidState The fluid state of the two-phase model
+     * \param phaseIdx Index of the fluid phase
+     * \param compIdx index of the component
+     */
+    template <class FluidState>
+    static Scalar fugacityCoefficient(const FluidState &fluidState,
+                                      int phaseIdx,
+                                      int compIdx)
+    {
+        assert(0 <= phaseIdx  && phaseIdx < numPhases);
+        assert(0 <= compIdx  && compIdx < numComponents);
+
+        if (phaseIdx == compIdx)
+            // We could calculate the real fugacity coefficient of
+            // the component in the fluid. Probably that's not worth
+            // the effort, since the fugacity coefficient of the other
+            // component is infinite anyway...
+            return 1.0;
+        return std::numeric_limits<Scalar>::infinity();
+    }
+
+    // using Base::diffusionCoefficient;
+    /*!
+     * \brief Calculate the binary molecular diffusion coefficient for
+     *        a component in a fluid phase \f$\mathrm{[mol^2 * s / (kg*m^3)]}\f$
+     * \param fluidState The fluid state of the two-phase model
+     * \param phaseIdx Index of the fluid phase
+     * \param compIdx index of the component
+     *
+     * Molecular diffusion of a compoent \f$\mathrm{\kappa}\f$ is caused by a
+     * gradient of the chemical potential and follows the law
+     *
+     * \f[ J = - D \mathbf{grad} \mu_\kappa \f]
+     *
+     * where \f$\mathrm{\mu_\kappa]}\f$ is the component's chemical potential,
+     * \f$\mathrm{D}\f$ is the diffusion coefficient and \f$\mathrm{J}\f$ is the
+     * diffusive flux. \f$\mathrm{\mu_\kappa}\f$ is connected to the component's
+     * fugacity \f$\mathrm{f_\kappa}\f$ by the relation
+     *
+     * \f[ \mu_\kappa = R T_\alpha \mathrm{ln} \frac{f_\kappa}{p_\alpha} \f]
+     *
+     * where \f$\mathrm{p_\alpha}\f$ and \f$\mathrm{T_\alpha}\f$ are the fluid phase'
+     * pressure and temperature.
+     */
+    template <class FluidState>
+    static Scalar diffusionCoefficient(const FluidState &fluidState,
+                                       int phaseIdx,
+                                       int compIdx)
+    {
+        DUNE_THROW(Dune::InvalidStateException,
+                   "Diffusion coefficients of components are meaningless if"
+                   " immiscibility is assumed");
+    }
+
+    using Base::binaryDiffusionCoefficient;
+    /*!
+     * \brief Given a phase's composition, temperature and pressure,
+     *        return the binary diffusion coefficient \f$\mathrm{[m^2/s]}\f$ for components
+     *        \f$\mathrm{i}\f$ and \f$\mathrm{j}\f$ in this phase.
+     * \param fluidState The fluid state of the two-phase model
+     * \param phaseIdx Index of the fluid phase
+     * \param compIIdx index of the component i
+     * \param compJIdx index of the component j
+     */
+    template <class FluidState>
+    static Scalar binaryDiffusionCoefficient(const FluidState &fluidState,
+                                             int phaseIdx,
+                                             int compIIdx,
+                                             int compJIdx)
+
+    {
+        DUNE_THROW(Dune::InvalidStateException,
+                   "Binary diffusion coefficients of components are meaningless if"
+                   " immiscibility is assumed");
+    }
+
+    using Base::enthalpy;
+    /*!
+     * \brief Return the specific enthalpy of a fluid phase \f$\mathrm{[J/kg]}\f$.
+     * \param fluidState The fluid state of the two-phase model
+     * \param phaseIdx Index of the fluid phase
+     */
+    template <class FluidState>
+    static Scalar enthalpy(const FluidState &fluidState,
+                                 int phaseIdx)
+    {
+        assert(0 <= phaseIdx  && phaseIdx < numPhases);
+
+        Scalar temperature = fluidState.temperature(phaseIdx);
+        Scalar pressure = fluidState.pressure(phaseIdx);
+
+        switch(phaseIdx)
+        {
+            case wPhaseIdx: return WettingFluid::enthalpy(temperature, pressure); break;
+            case nPhaseIdx: return NonwettingFluid::enthalpy(temperature, pressure); break;
+            case gPhaseIdx: return Gas::enthalpy(temperature, pressure); break;
+            default: DUNE_THROW(Dune::InvalidStateException, "Invalid phase index");
+        }
+    }
+
+    using Base::thermalConductivity;
+    /*!
+     * \brief Thermal conductivity of a fluid phase \f$\mathrm{[W/(m K)]}\f$.
+     * \param fluidState The fluid state of the two-phase model
+     * \param phaseIdx Index of the fluid phase
+     */
+    template <class FluidState>
+    static Scalar thermalConductivity(const FluidState &fluidState,
+                                      int phaseIdx)
+    {
+        assert(0 <= phaseIdx  && phaseIdx < numPhases);
+
+        Scalar temperature = fluidState.temperature(phaseIdx);
+        Scalar pressure = fluidState.pressure(phaseIdx);
+
+        switch(phaseIdx)
+        {
+            case wPhaseIdx: return WettingFluid::thermalConductivity(temperature, pressure); break;
+            case nPhaseIdx: return NonwettingFluid::thermalConductivity(temperature, pressure); break;
+            case gPhaseIdx: return Gas::thermalConductivity(temperature, pressure); break;
+            default: DUNE_THROW(Dune::InvalidStateException, "Invalid phase index");
+        }
+    }
+
+    using Base::heatCapacity;
+    /*!
+     * @copybrief Base::thermalConductivity
+     *
+     * Additional comments:
+     *
+     * Specific isobaric heat capacity of a fluid phase.
+     *        \f$\mathrm{[J/(kg*K)]}\f$.
+     *
+     * \param fluidState The fluid state of the two-phase model
+     * \param phaseIdx for which phase to give back the heat capacity
+     */
+    template <class FluidState>
+    static Scalar heatCapacity(const FluidState &fluidState,
+                               int phaseIdx)
+    {
+        assert(0 <= phaseIdx  && phaseIdx < numPhases);
+
+        Scalar temperature = fluidState.temperature(phaseIdx);
+        Scalar pressure = fluidState.pressure(phaseIdx);
+
+        switch(phaseIdx)
+        {
+            case wPhaseIdx: return WettingFluid::heatCapacity(temperature, pressure); break;
+            case nPhaseIdx: return NonwettingFluid::heatCapacity(temperature, pressure); break;
+            case gPhaseIdx: return Gas::heatCapacity(temperature, pressure); break;
+            default: DUNE_THROW(Dune::InvalidStateException, "Invalid phase index");
+        }
+    }
+};
+
+} // end namespace FluidSystems
+} // end namespace Dumux
+
+#endif