diff --git a/dune/gdt/operators/lincomb.hh b/dune/gdt/operators/lincomb.hh
new file mode 100644
index 0000000000000000000000000000000000000000..89d5b7d991fd926ea54a1867c9a55b895b6e4b18
--- /dev/null
+++ b/dune/gdt/operators/lincomb.hh
@@ -0,0 +1,304 @@
+// This file is part of the dune-gdt project:
+//   https://github.com/dune-community/dune-gdt
+// Copyright 2010-2018 dune-gdt developers and contributors. All rights reseVed.
+// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
+//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
+//          with "runtime exception" (http://www.dune-project.org/license.html)
+// Authors:
+//   Felix Schindler (2018)
+
+#ifndef DUNE_GDT_const_operators_LINCOMB_HH
+#define DUNE_GDT_const_operators_LINCOMB_HH
+
+#include <vector>
+
+#include <dune/xt/common/memory.hh>
+#include <dune/xt/la/container.hh>
+
+#include "interfaces.hh"
+
+namespace Dune {
+namespace GDT {
+
+
+/**
+ * \todo Add handling of parametric operators: merge this->parameter_type() and op.parameter_type() upon add().
+ */
+template <class M, class SGV, size_t s_r = 1, size_t s_rC = 1, size_t r_r = s_r, size_t r_rC = s_rC, class RGV = SGV>
+class ConstLincombOperator : public OperatorInterface<M, SGV, s_r, s_rC, r_r, r_rC, RGV>
+{
+  using ThisType = ConstLincombOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>;
+  using BaseType = OperatorInterface<M, SGV, s_r, s_rC, r_r, r_rC, RGV>;
+
+public:
+  using typename BaseType::SourceSpaceType;
+  using typename BaseType::RangeSpaceType;
+  using typename BaseType::FieldType;
+  using typename BaseType::MatrixOperatorType;
+  using typename BaseType::VectorType;
+
+  using OperatorType = BaseType;
+
+  ConstLincombOperator(const SourceSpaceType& src_space, const RangeSpaceType& rng_space)
+    : source_space_(src_space)
+    , range_space_(rng_space)
+  {
+  }
+
+  void add(const OperatorType& op, const FieldType& coeff = 1.)
+  {
+    const_operators_.emplace_back(op);
+    coeffs_.emplace_back(coeff);
+  }
+
+  void add(const OperatorType*&& op, const FieldType& coeff = 1.)
+  {
+    const_operators_.emplace_back(std::move(op));
+    coeffs_.emplace_back(coeff);
+  }
+
+  size_t num_ops() const
+  {
+    return const_operators_.size();
+  }
+
+  const OperatorType& op(const size_t ii) const
+  {
+    DUNE_THROW_IF(ii >= this->num_ops(),
+                  Exceptions::operator_error,
+                  "ii = " << ii << "\n   this->num_ops() = " << this->num_ops());
+    return const_operators_[ii].access();
+  }
+
+  const FieldType& coeff(const size_t ii) const
+  {
+    DUNE_THROW_IF(ii >= this->num_ops(),
+                  Exceptions::operator_error,
+                  "ii = " << ii << "\n   this->num_ops() = " << this->num_ops());
+    return coeffs_[ii];
+  }
+
+  bool linear() const override final
+  {
+    for (const auto& op : const_operators_)
+      if (!op.access().linear())
+        return false;
+    return true;
+  }
+
+  const SourceSpaceType& source_space() const override final
+  {
+    return source_space_;
+  }
+
+  const RangeSpaceType& range_space() const override final
+  {
+    return range_space_;
+  }
+
+  using BaseType::apply;
+
+  void apply(const VectorType& source, VectorType& range, const XT::Common::Parameter& param = {}) const
+  {
+    range.set_all(0);
+    auto tmp = range;
+    for (size_t ii = 0; ii < this->num_ops(); ++ii) {
+      this->op(ii).apply(source, tmp, param);
+      tmp *= this->coeff(ii);
+      range += tmp;
+    }
+  } // ... append(...)
+
+  std::vector<std::string> invert_options() const
+  {
+    DUNE_THROW(Exceptions::operator_error, "This operator is not invertible!");
+    return std::vector<std::string>();
+  }
+
+  XT::Common::Configuration invert_options(const std::string& /*type*/) const
+  {
+    DUNE_THROW(Exceptions::operator_error, "This operator is not invertible!");
+    return XT::Common::Configuration();
+  }
+
+  void apply_inverse(const VectorType& /*range*/,
+                     VectorType& /*source*/,
+                     const XT::Common::Configuration& /*opts*/,
+                     const XT::Common::Parameter& /*param*/ = {}) const
+  {
+    DUNE_THROW(Exceptions::operator_error, "This operator is not invertible!");
+  }
+
+  std::vector<std::string> jacobian_options() const
+  {
+    return {"lincomb"};
+  }
+
+  XT::Common::Configuration jacobian_options(const std::string& type) const
+  {
+    DUNE_THROW_IF(type != this->jacobian_options().at(0), Exceptions::operator_error, "type = " << type);
+    using XT::Common::to_string;
+    XT::Common::Configuration ret({{"type", type}});
+    for (size_t ii = 0; ii < this->num_ops(); ++ii) {
+      for (auto&& tp : this->op(ii).jacobian_options())
+        ret["op_" + to_string(ii) + ".types"] += ", " + tp;
+      ret.add(this->op(ii).jacobian_options(this->op(ii).jacobian_options().at(0)), "op_" + to_string(ii) + ".opts");
+    }
+    for (size_t ii = 0; ii < this->num_ops(); ++ii) {
+      const auto back_ii = ssize_t(this->num_ops()) - 1 - ssize_t(ii);
+      for (auto&& tp : this->op(back_ii).jacobian_options())
+        ret["back_op_" + to_string(back_ii) + ".types"] += ", " + tp;
+      ret.add(this->op(back_ii).jacobian_options(this->op(back_ii).jacobian_options().at(0)),
+              "back_op_" + to_string(back_ii) + ".opts");
+    }
+    return ret;
+  } // ... jacobian_options(...)
+
+  using BaseType::jacobian;
+
+  void jacobian(const VectorType& source,
+                MatrixOperatorType& jacobian_op,
+                const XT::Common::Configuration& opts,
+                const XT::Common::Parameter& param = {}) const
+  {
+    // some checks
+    DUNE_THROW_IF(!source.valid(), Exceptions::operator_error, "source contains inf or nan!");
+    DUNE_THROW_IF(!(this->parameter_type() <= param.type()),
+                  Exceptions::operator_error,
+                  "this->parameter_type() = " << this->parameter_type() << "\n   param.type() = " << param.type());
+    DUNE_THROW_IF(!opts.has_key("type"), Exceptions::operator_error, opts);
+    DUNE_THROW_IF(opts.get<std::string>("type") != jacobian_options().at(0), Exceptions::operator_error, opts);
+    using XT::Common::to_string;
+    const XT::Common::Configuration default_opts = this->jacobian_options(this->jacobian_options().at(0));
+    for (size_t ii = 0; ii < this->num_ops(); ++ii) {
+      // parse opts
+      XT::Common::Configuration op_opts;
+      if (opts.has_sub("op_" + to_string(ii) + ".opts")) {
+        if (opts.sub("op_" + to_string(ii) + ".opts") != default_opts.sub("op_" + to_string(ii) + ".opts"))
+          op_opts = opts.sub("op_" + to_string(ii) + ".opts");
+      }
+      const auto back_ii = ssize_t(this->num_ops()) - 1 - ssize_t(ii);
+      if (opts.has_sub("back_op_" + to_string(back_ii) + ".opts")) {
+        if (opts.sub("back_op_" + to_string(back_ii) + ".opts")
+            != default_opts.sub("back_op_" + to_string(back_ii) + ".opts")) {
+          DUNE_THROW_IF(opts.has_sub("op_" + to_string(ii) + ".opts"),
+                        Exceptions::operator_error,
+                        "Cannot define opts for operator " << ii << " by specifying op_" << ii << ".opts and back_op_"
+                                                           << (back_ii)
+                                                           << ".opts at the same time!\n\n\nopts = \n"
+                                                           << opts);
+          op_opts = opts.sub("back_op_" + to_string(back_ii) + ".opts");
+        }
+      }
+      if (op_opts.empty())
+        op_opts["type"] = this->op(ii).jacobian_options().at(0);
+      // save curent scaling
+      const auto scaling = jacobian_op.scaling;
+      // add op
+      jacobian_op.scaling *= this->coeff(ii);
+      this->op(ii).jacobian(source, jacobian_op, op_opts, param);
+      // restore scaling
+      jacobian_op.scaling = scaling;
+    }
+  } // ... jacobian(...)
+
+private:
+  const SourceSpaceType& source_space_;
+  const RangeSpaceType& range_space_;
+  std::vector<XT::Common::ConstStorageProvider<OperatorType>> const_operators_;
+  std::vector<FieldType> coeffs_;
+}; // class ConstLincombOperator
+
+
+template <class Matrix, class GV, size_t r, size_t rC, class F>
+std::enable_if_t<XT::LA::is_matrix<Matrix>::value, ConstLincombOperator<Matrix, GV, r, rC>>
+make_const_lincomb_operator(const SpaceInterface<GV, r, rC, F>& space)
+{
+  return ConstLincombOperator<Matrix, GV, r, rC>(space, space);
+}
+
+
+template <class GV, size_t r, size_t rC, class F>
+ConstLincombOperator<typename XT::LA::Container<F>::MatrixType, GV, r, rC>
+make_const_lincomb_operator(const SpaceInterface<GV, r, rC, F>& space)
+{
+  return ConstLincombOperator<typename XT::LA::Container<F>::MatrixType, GV, r, rC>(space, space);
+}
+
+
+template <class M, class SGV, size_t s_r = 1, size_t s_rC = 1, size_t r_r = s_r, size_t r_rC = s_rC, class RGV = SGV>
+class LincombOperator : public ConstLincombOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>
+{
+  using ThisType = LincombOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>;
+  using BaseType = ConstLincombOperator<M, SGV, s_r, s_rC, r_r, r_rC, RGV>;
+
+public:
+  using typename BaseType::SourceSpaceType;
+  using typename BaseType::RangeSpaceType;
+  using typename BaseType::FieldType;
+  using typename BaseType::MatrixOperatorType;
+  using typename BaseType::VectorType;
+
+  using OperatorType = OperatorInterface<M, SGV, s_r, s_rC, r_r, r_rC, RGV>;
+
+  LincombOperator(const SourceSpaceType& src_space, const RangeSpaceType& rng_space)
+    : BaseType(src_space, rng_space)
+  {
+  }
+
+  using BaseType::add;
+
+  void add(OperatorType& op, const FieldType& coeff = 1.)
+  {
+    operators_.emplace_back(op);
+    BaseType::add(operators_.back().access(), coeff);
+  }
+
+  void add(OperatorType*&& op, const FieldType& coeff = 1.)
+  {
+    operators_.emplace_back(std::move(op));
+    BaseType::add(operators_.back().access(), coeff);
+  }
+
+  using BaseType::op;
+
+  OperatorType& op(const size_t ii)
+  {
+    DUNE_THROW_IF(ii >= this->num_ops(),
+                  Exceptions::operator_error,
+                  "ii = " << ii << "\n   this->num_ops() = " << this->num_ops());
+    return operators_[ii].access();
+  }
+
+  OperatorType& assemble(const bool use_tbb = false)
+  {
+    for (auto& op : operators_)
+      op.access().assemble(use_tbb);
+    return *this;
+  }
+
+private:
+  std::vector<XT::Common::StorageProvider<OperatorType>> operators_;
+}; // class LincombOperator
+
+
+template <class Matrix, class GV, size_t r, size_t rC, class F>
+std::enable_if_t<XT::LA::is_matrix<Matrix>::value, LincombOperator<Matrix, GV, r, rC>>
+make_lincomb_operator(const SpaceInterface<GV, r, rC, F>& space)
+{
+  return LincombOperator<Matrix, GV, r, rC>(space, space);
+}
+
+
+template <class GV, size_t r, size_t rC, class F>
+LincombOperator<typename XT::LA::Container<F>::MatrixType, GV, r, rC>
+make_lincomb_operator(const SpaceInterface<GV, r, rC, F>& space)
+{
+  return LincombOperator<typename XT::LA::Container<F>::MatrixType, GV, r, rC>(space, space);
+}
+
+
+} // namespace GDT
+} // namespace Dune
+
+#endif // DUNE_GDT_const_operators_LINCOMB_HH