diff --git a/dumux/common/typetraits/CMakeLists.txt b/dumux/common/typetraits/CMakeLists.txt
index 41bd98a128d5fd2838094159a187e34828d5dc4a..f71dd84a50c7ae4e60327b1ecb0ea273ebb15675 100644
--- a/dumux/common/typetraits/CMakeLists.txt
+++ b/dumux/common/typetraits/CMakeLists.txt
@@ -2,4 +2,5 @@
 install(FILES
 matrix.hh
 vector.hh
+isvalid.hh
 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/common/typetraits)
diff --git a/dumux/common/typetraits/isvalid.hh b/dumux/common/typetraits/isvalid.hh
new file mode 100644
index 0000000000000000000000000000000000000000..4be5daa17fd4137c9ef3d9a6a6ec09cbdde8c997
--- /dev/null
+++ b/dumux/common/typetraits/isvalid.hh
@@ -0,0 +1,99 @@
+// -*- 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 Common
+ * \ingroup TypeTraits
+ * \brief A helper function for class member function introspection
+ * \note Follows the description by Jean Guegant on
+ *       https://jguegant.github.io/blogs/tech/sfinae-introduction.html
+ */
+#ifndef DUMUX_TYPETRAITS_ISVALID_HH
+#define DUMUX_TYPETRAITS_ISVALID_HH
+
+#include <type_traits>
+
+namespace Dumux {
+
+namespace Impl {
+
+// the functor testing an expression for validity
+// Expression: can be for example a lambda expression
+template <typename Expression>
+struct ValidityTestFunctor
+{
+private:
+    // std::declval creates an object of expression
+    // the expression, i.e. a lambda expression gets an object as a parameter and does checks on it.
+    // so we create also an object of the parameter usiung std::declval
+    // if decltype can evaluate the type, i.e. the object parameter is a valid argument for the expression
+    // we return std::true_type
+    // note: the int is used to give the first overload always precedence
+    // note: the last argument in decltype determines the deduced type but all types need to be valid
+    template <typename Argument>
+    constexpr auto testArgument_(int /* unused int to make this overload the priority choice */) const
+    -> decltype(std::declval<Expression>()(std::declval<Argument>()), std::true_type())
+    { return std::true_type(); }
+
+    // otherwise we return std::false_type, i.e. this is the fallback
+    template <typename Argument>
+    constexpr std::false_type testArgument_(...) const
+    { return std::false_type(); }
+
+public:
+    // the operator () takes the argument we want to use as argument to the test expression
+    // note we use the int to prefer the "valid"-result overload of test_ if possible
+    template <typename Argument>
+    constexpr auto operator() (const Argument& arg) const
+    { return testArgument_<Argument>(int()); }
+
+    // check function takes the template argument explicitly
+    template <typename Argument>
+    constexpr auto check () const
+    { return testArgument_<Argument>(int()); }
+};
+
+} // end namespace Impl
+
+
+/*!
+ * \ingroup Common
+ * \ingroup TypeTraits
+ * \brief A function that creates a test functor to do class member introspection at compile time
+ * \return a functor that returns true if the expression is valid with a given type / object
+ * Usage:
+ * If you want to test if a class has the member function resize(std::size_t) create a test functor
+ * \code
+ * constexpr auto hasResize = isValid([](auto&& c) -> decltype(c.resize(std::size_t(1))) {}; });
+ * \endcode
+ * The you can use the test in compile time expressions
+ * \code
+ * template<class T>
+ * auto otherFunc(const T& t)
+ * -> typename std::enable_if_t<!decltype(hasResize(myvector))::value, double>
+ * { return 4.0; }
+ * \endcode
+ */
+template <typename Expression>
+constexpr auto isValid(const Expression& t)
+{ return Impl::ValidityTestFunctor<Expression>(); }
+
+} // end namespace Dumux
+
+#endif
diff --git a/test/common/CMakeLists.txt b/test/common/CMakeLists.txt
index ea0bdb19633e37b326a1675139f36d13c0f6afd4..6d8f4f2ea9f7328a92665453b2fe85f4155fcdf9 100644
--- a/test/common/CMakeLists.txt
+++ b/test/common/CMakeLists.txt
@@ -4,3 +4,4 @@ add_subdirectory(math)
 add_subdirectory(parameters)
 add_subdirectory(propertysystem)
 add_subdirectory(spline)
+add_subdirectory(typetraits)
diff --git a/test/common/typetraits/CMakeLists.txt b/test/common/typetraits/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..48df1479fd3bd5e3a7de18601a5abd58a9b37b06
--- /dev/null
+++ b/test/common/typetraits/CMakeLists.txt
@@ -0,0 +1 @@
+dune_add_test(SOURCES test_isvalid.cc)
diff --git a/test/common/typetraits/test_isvalid.cc b/test/common/typetraits/test_isvalid.cc
new file mode 100644
index 0000000000000000000000000000000000000000..996bfaa92246532566ea80479958b918d3636345
--- /dev/null
+++ b/test/common/typetraits/test_isvalid.cc
@@ -0,0 +1,73 @@
+#include <config.h>
+
+#include <iostream>
+#include <dumux/common/typetraits/isvalid.hh>
+
+namespace Dumux {
+namespace Test {
+
+struct MyVector {
+public:
+    void resize(std::size_t i) {};
+
+    void resize(std::size_t i) const {};
+
+    void resize() {};
+};
+
+struct MyOtherVector {
+    double resize;
+};
+
+constexpr auto hasResize = Dumux::isValid([](auto&& a) -> decltype(a.resize(std::size_t(1))) { });
+
+// using the check function
+template<class Vector, typename std::enable_if_t<hasResize.template check<Vector>(), int> = 0>
+void resize(const Vector& v, std::size_t size)
+{
+    v.resize(size); std::cout << "-> resized resizeable vector! size: " << size << std::endl;
+}
+
+// using decltype + declval and operator ()
+template<class Vector, typename std::enable_if_t<!decltype(hasResize(std::declval<Vector>()))::value, int> = 0>
+void resize(const Vector& v, std::size_t size)
+{
+    std::cout << "-> Did not resize non-resizeable vector!" << std::endl;
+}
+
+// using trailing return type and operator ()
+template<class Vector>
+auto resize2(const Vector& v, std::size_t size)
+-> typename std::enable_if_t<decltype(hasResize(v))::value, void>
+{
+    v.resize(size); std::cout << "-> resized resizeable vector! size: " << size << std::endl;
+}
+
+// using trailing return type and operator ()
+template<class Vector>
+auto resize2(const Vector& v, std::size_t size)
+-> typename std::enable_if_t<!hasResize.template check<Vector>(), void>
+{
+    std::cout << "-> Did not resize non-resizeable vector!" << std::endl;
+}
+
+} // end namespace Test
+} // end namespace Dumux
+
+int main(int argc, char* argv[])
+{
+    using namespace Dumux::Test;
+
+    MyVector v0;
+    MyOtherVector v1;
+
+    static_assert(hasResize(v0), "Vector v0 doesn't have a resize function!");
+    static_assert(!hasResize(v1), "False positive. v1 has no resize function!");
+
+    resize(v0, 3);
+    resize(v1, 3);
+    resize2(v0, 10);
+    resize2(v1, 10);
+
+    return 0;
+}