diff --git a/CHANGELOG.md b/CHANGELOG.md
index ed9fe0f88cb8922604e52e23f45f53e6133abfb8..fc8aefdb120826cf92dd426b05c2ca052e7e2bc5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
 # Master (will become release 2.10)
 
+- The class `Dune::FEAssembler` has been removed -- please use `Dune::Elasticity::FEAssembler`
+  from now on.  The removed code still used the old `dune-fufem` function space basis interface.
+
 
 # Release 2.9
 
diff --git a/dune/elasticity/assemblers/feassembler.hh b/dune/elasticity/assemblers/feassembler.hh
index 8b922c6fc0f7eb43a6264899396d1b5734a18898..e7f062db00cf3573413aec7dc37092c38d2e8b18 100644
--- a/dune/elasticity/assemblers/feassembler.hh
+++ b/dune/elasticity/assemblers/feassembler.hh
@@ -218,188 +218,4 @@ computeEnergy(const VectorType& configuration) const
 
 } // namespace Dune::Elasticity
 
-
-
-namespace Dune
-{
-
-/** \brief A global FE assembler for variational problems (old fufem bases version)
- */
-template <class Basis, class VectorType >
-class
-FEAssembler
-{
-
-    typedef typename Basis::GridView GridView;
-
-    //! Dimension of the grid.
-    enum { gridDim = GridView::dimension };
-
-    //! Dimension of a tangent space
-    enum { blocksize = VectorType::value_type::dimension };
-
-    //!
-    typedef Dune::FieldMatrix<double, blocksize, blocksize> MatrixBlock;
-
-public:
-    [[deprecated("dune-elasticity with dune-fufem bases is now deprecated. Use Elasticity::FEAssembler with dune-functions bases.")]]
-    const Basis basis_;
-
-    /** \brief Partition type on which to assemble
-     *
-     * We want a fully nonoverlapping partition, and therefore need to skip ghost elements.
-     */
-    static constexpr auto partitionType = Dune::Partitions::interiorBorder;
-
-protected:
-
-    LocalFEStiffness<GridView,
-                             typename Basis::LocalFiniteElement,
-                             VectorType>* localStiffness_;
-
-public:
-
-    /** \brief Constructor for a given grid */
-    FEAssembler(const Basis& basis,
-                LocalFEStiffness<GridView,typename Basis::LocalFiniteElement, VectorType>* localStiffness)
-        : basis_(basis),
-          localStiffness_(localStiffness)
-    {}
-
-    /** \brief Assemble the tangent stiffness matrix and the functional gradient together
-     *
-     * This may be more efficient than computing them separately
-     */
-    virtual void assembleGradientAndHessian(const VectorType& sol,
-                                            Dune::BlockVector<Dune::FieldVector<double, blocksize> >& gradient,
-                                            Dune::BCRSMatrix<MatrixBlock>& hessian,
-                                            bool computeOccupationPattern=true) const;
-
-    /** \brief Compute the energy of a deformation state */
-    virtual double computeEnergy(const VectorType& sol) const;
-
-    //protected:
-    void getNeighborsPerVertex(Dune::MatrixIndexSet& nb) const;
-
-}; // end class
-
-
-
-template <class Basis, class TargetSpace>
-void FEAssembler<Basis,TargetSpace>::
-getNeighborsPerVertex(Dune::MatrixIndexSet& nb) const
-{
-    int n = basis_.size();
-
-    nb.resize(n, n);
-
-    for (const auto& element : elements(basis_.getGridView(), partitionType))
-    {
-        const typename Basis::LocalFiniteElement& lfe = basis_.getLocalFiniteElement(element);
-
-        for (size_t i=0; i<lfe.localBasis().size(); i++) {
-
-            for (size_t j=0; j<lfe.localBasis().size(); j++) {
-
-                int iIdx = basis_.index(element,i);
-                int jIdx = basis_.index(element,j);
-
-                nb.add(iIdx, jIdx);
-
-            }
-
-        }
-
-    }
-
-}
-
-template <class Basis, class VectorType>
-void FEAssembler<Basis,VectorType>::
-assembleGradientAndHessian(const VectorType& sol,
-                           Dune::BlockVector<Dune::FieldVector<double, blocksize> >& gradient,
-                           Dune::BCRSMatrix<MatrixBlock>& hessian,
-                           bool computeOccupationPattern) const
-{
-    if (computeOccupationPattern) {
-
-        Dune::MatrixIndexSet neighborsPerVertex;
-        getNeighborsPerVertex(neighborsPerVertex);
-        neighborsPerVertex.exportIdx(hessian);
-
-    }
-
-    hessian = 0;
-
-    gradient.resize(sol.size());
-    gradient = 0;
-
-    for (const auto& element : elements(basis_.getGridView(), partitionType))
-    {
-        const int numOfBaseFct = basis_.getLocalFiniteElement(element).localBasis().size();
-
-        // Extract local solution
-        VectorType localSolution(numOfBaseFct);
-        VectorType localPointLoads(numOfBaseFct);
-
-        for (int i=0; i<numOfBaseFct; i++)
-            localSolution[i]   = sol[basis_.index(element,i)];
-
-        VectorType localGradient(numOfBaseFct);
-
-        // setup local matrix and gradient
-        localStiffness_->assembleGradientAndHessian(element, basis_.getLocalFiniteElement(element), localSolution, localGradient);
-
-        // Add element matrix to global stiffness matrix
-        for(int i=0; i<numOfBaseFct; i++) {
-
-            int row = basis_.index(element,i);
-
-            for (int j=0; j<numOfBaseFct; j++ ) {
-
-                int col = basis_.index(element,j);
-                hessian[row][col] += localStiffness_->A_[i][j];
-
-            }
-        }
-
-        // Add local gradient to global gradient
-        for (int i=0; i<numOfBaseFct; i++)
-            gradient[basis_.index(element,i)] += localGradient[i];
-
-    }
-
-}
-
-
-template <class Basis, class VectorType>
-double FEAssembler<Basis, VectorType>::
-computeEnergy(const VectorType& sol) const
-{
-    double energy = 0;
-
-    if (sol.size()!=basis_.size())
-        DUNE_THROW(Dune::Exception, "Solution vector doesn't match the basis!");
-
-    // Loop over all elements
-    for (const auto& element : elements(basis_.getGridView(), partitionType))
-    {
-        // Number of degrees of freedom on this element
-        size_t nDofs = basis_.getLocalFiniteElement(element).localBasis().size();
-
-        VectorType localSolution(nDofs);
-
-        for (size_t i=0; i<nDofs; i++)
-            localSolution[i]   = sol[basis_.index(element,i)];
-
-        energy += localStiffness_->energy(element, basis_.getLocalFiniteElement(element), localSolution);
-
-    }
-
-    return energy;
-
-}
-
-} // namespace Dune
-
 #endif
diff --git a/dune/elasticity/common/trustregionsolver.cc b/dune/elasticity/common/trustregionsolver.cc
index 7e9fb980840c64a4c1959603c0b92ea301357b47..ef683c5c07cc49f5d308c515fc89d8c902de15af 100644
--- a/dune/elasticity/common/trustregionsolver.cc
+++ b/dune/elasticity/common/trustregionsolver.cc
@@ -6,7 +6,6 @@
 
 #include <dune/functions/functionspacebases/lagrangebasis.hh>
 
-#include <dune/fufem/functionspacebases/dunefunctionsbasis.hh>
 #include <dune/fufem/assemblers/operatorassembler.hh>
 #include <dune/fufem/assemblers/dunefunctionsoperatorassembler.hh>
 #include <dune/fufem/assemblers/localassemblers/laplaceassembler.hh>
@@ -20,8 +19,8 @@
 #include <dune/solvers/transferoperators/truncatedcompressedmgtransfer.hh>
 #include <dune/solvers/transferoperators/mandelobsrestrictor.hh>
 #include <dune/solvers/solvers/iterativesolver.hh>
+#include <dune/solvers/norms/energynorm.hh>
 #include <dune/solvers/norms/twonorm.hh>
-#include <dune/solvers/norms/h1seminorm.hh>
 
 #include <dune/elasticity/common/maxnormtrustregion.hh>
 
@@ -29,10 +28,7 @@
 template <class BasisType, class VectorType>
 void TrustRegionSolver<BasisType,VectorType>::
 setup(const typename BasisType::GridView::Grid& grid,
-         std::conditional_t< // do we have a dune-functions basis? -> choose right assembler type
-           Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>(),
-             const Dune::Elasticity::FEAssembler<BasisType,VectorType>*,
-             const Dune::FEAssembler<DuneFunctionsBasis<BasisType>,VectorType>* > assembler,
+         const Dune::Elasticity::FEAssembler<BasisType,VectorType>* assembler,
          const SolutionType& x,
          const Dune::BitSetVector<blocksize>& dirichletNodes,
          double tolerance,
@@ -71,10 +67,7 @@ setup(const typename BasisType::GridView::Grid& grid,
 
     BasisType feBasis(grid.levelGridView(grid.maxLevel()));
 
-    std::conditional_t< // do we have a dune-functions basis? -> choose right assembler type
-      Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>(),
-        BasisType,
-        DuneFunctionsBasis<BasisType> > basis(feBasis);
+    BasisType basis(feBasis);
 
     innerMultigridStep_ = std::make_unique<Dune::ParMG::Multigrid<VectorType> >();
     innerMultigridStep_->mu_ = mu;
@@ -85,10 +78,7 @@ setup(const typename BasisType::GridView::Grid& grid,
         std::cout << "Parallel multigrid setup took " << setupTimer.stop() << " seconds." << std::endl;
 #else
 
-    std::conditional_t< // do we have a dune-functions basis?
-      Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>(),
-        BasisType,
-        DuneFunctionsBasis<BasisType> > basis(assembler_->basis_);
+    BasisType basis(assembler_->basis_);
     // ////////////////////////////////
     //   Create a multigrid solver
     // ////////////////////////////////
@@ -131,123 +121,44 @@ setup(const typename BasisType::GridView::Grid& grid,
     // //////////////////////////////////////////////////////////////////////////////////////
 
 
-    using ScalarMatrixType = Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> >;
-    ScalarMatrixType localA;
+    MatrixType localA;
 
-    std::conditional_t< // do we have a dune-functions basis?
-      Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>(),
-        Dune::Fufem::DuneFunctionsOperatorAssembler<BasisType,BasisType>,
-        OperatorAssembler<DuneFunctionsBasis<BasisType>,DuneFunctionsBasis<BasisType>,Dune::Partitions::Interior> > operatorAssembler(basis,basis);
+    Dune::Fufem::DuneFunctionsOperatorAssembler operatorAssembler(basis,basis);
 
-    if constexpr ( Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>() )
-    {
-      using FiniteElement = std::decay_t<decltype(basis.localView().tree().child(0).finiteElement())>;
-      // construct a Fufem Basis Assembler
-      auto laplaceStiffness = LaplaceAssembler<GridType, FiniteElement, FiniteElement, Dune::ScaledIdentityMatrix<double,dim>>();
-      // transform it to a dune-functions assembler
-      auto localAssembler = [&](const auto& element, auto& localMatrix, auto&& trialLocalView, auto&& ansatzLocalView){
-        // the fufem basis assembler assumes a scalar basis but a blocked element matrix!
-        // we can use ScaledIdentityMatrix here
-        Dune::Matrix<Dune::ScaledIdentityMatrix<double,dim>> localBlockedMatrix( localMatrix.N()/dim, localMatrix.M()/dim );
-        laplaceStiffness.assemble(element,
-                                  localBlockedMatrix,
-                                  trialLocalView.tree().child(0).finiteElement(),
-                                  ansatzLocalView.tree().child(0).finiteElement());
-        // convert back to flat matrix (we need only the diagonal entries in the blocks)
-        localMatrix = 0;
-        for(size_t i=0; i<localBlockedMatrix.N(); i++)
-          for(size_t j=0; j<localBlockedMatrix.M(); j++)
-            Dune::MatrixVector::addToDiagonal(localMatrix[i*dim][j*dim], localBlockedMatrix[i][j].scalar());
-      };
-
-
-      auto matrixBackend = Dune::Fufem::istlMatrixBackend(localA);
-      auto patternBuilder = matrixBackend.patternBuilder();
-
-      operatorAssembler.assembleBulkPattern(patternBuilder);
-      patternBuilder.setupMatrix();
-
-      operatorAssembler.assembleBulkEntries(matrixBackend, localAssembler);
-    }
-    else
-    {
-      LaplaceAssembler<GridType,
-                      typename DuneFunctionsBasis<BasisType>::LocalFiniteElement,
-                      typename DuneFunctionsBasis<BasisType>::LocalFiniteElement> laplaceStiffness;
+    Dune::Fufem::LaplaceAssembler laplaceStiffness;
 
-      operatorAssembler.assemble(laplaceStiffness, localA);
-    }
+    operatorAssembler.assembleBulk(Dune::Fufem::istlMatrixBackend(localA), laplaceStiffness);
 
-    ScalarMatrixType* A = new ScalarMatrixType(localA);
+    MatrixType* A = new MatrixType(localA);
 
-    h1SemiNorm_ = std::make_shared< H1SemiNorm<CorrectionType> >(*A);
+    h1SemiNorm_ = std::make_shared<EnergyNorm<MatrixType, CorrectionType> >(*A);
 
     // //////////////////////////////////////////////////////////////////////////////////////
     //   Assemble a mass matrix to create a norm that's equivalent to the L2-norm
     //   This will be used to monitor the gradient
     // //////////////////////////////////////////////////////////////////////////////////////
 
-    ScalarMatrixType localMassMatrix;
+    MatrixType localMassMatrix;
 
-    if constexpr ( Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>() )
-    {
-      // construct a Fufem Basis Assembler
-      using FiniteElement = std::decay_t<decltype(basis.localView().tree().child(0).finiteElement())>;
-      auto massStiffness = MassAssembler<GridType, FiniteElement, FiniteElement, Dune::ScaledIdentityMatrix<double,dim>>();
-      // transform it to a dune-functions assembler
-      auto localMassAssembler = [&](const auto& element, auto& localMatrix, auto&& trialLocalView, auto&& ansatzLocalView){
-        // the fufem basis assembler assumes a scalar basis but a blocked element matrix!
-        // we can use ScaledIdentityMatrix here
-        Dune::Matrix<Dune::ScaledIdentityMatrix<double,dim>> localBlockedMatrix( localMatrix.N()/dim, localMatrix.M()/dim );
-        massStiffness.assemble(element,
-                               localBlockedMatrix,
-                               trialLocalView.tree().child(0).finiteElement(),
-                               ansatzLocalView.tree().child(0).finiteElement());
-        // convert back to flat matrix (we need only the diagonal entries in the blocks)
-        localMatrix = 0;
-        for(size_t i=0; i<localBlockedMatrix.N(); i++)
-          for(size_t j=0; j<localBlockedMatrix.M(); j++)
-            Dune::MatrixVector::addToDiagonal(localMatrix[i*dim][j*dim], localBlockedMatrix[i][j].scalar());
-      };
-
-      auto massMatrixBackend = Dune::Fufem::istlMatrixBackend(localMassMatrix);
-      auto massPatternBuilder = massMatrixBackend.patternBuilder();
-
-      operatorAssembler.assembleBulkPattern(massPatternBuilder);
-      massPatternBuilder.setupMatrix();
-
-      operatorAssembler.assembleBulkEntries(massMatrixBackend, localMassAssembler);
-    }
-    else
-    {
-      MassAssembler<GridType,
-                    typename DuneFunctionsBasis<BasisType>::LocalFiniteElement,
-                    typename DuneFunctionsBasis<BasisType>::LocalFiniteElement> massStiffness;
+    Dune::Fufem::MassAssembler massStiffness;
 
-      operatorAssembler.assemble(massStiffness, localMassMatrix);
-    }
+    operatorAssembler.assembleBulk(Dune::Fufem::istlMatrixBackend(localMassMatrix), massStiffness);
+
+    MatrixType* massMatrix = new MatrixType(localMassMatrix);
 
-    ScalarMatrixType* massMatrix = new ScalarMatrixType(localMassMatrix);
-    l2Norm_ = std::make_shared<H1SemiNorm<CorrectionType> >(*massMatrix);
+    l2Norm_ = std::make_shared<EnergyNorm<MatrixType, CorrectionType> >(*massMatrix);
 
     // ////////////////////////////////////////////////////////////
     //    Create Hessian matrix and its occupation structure
     // ////////////////////////////////////////////////////////////
 
     hessianMatrix_ = std::make_shared<MatrixType>();
-    if constexpr ( Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>() )
-    {
-      auto hessianBackend = Dune::Fufem::istlMatrixBackend(*hessianMatrix_);
-      auto hessianPatternBuilder = hessianBackend.patternBuilder();
-      operatorAssembler.assembleBulkPattern(hessianPatternBuilder);
-      hessianPatternBuilder.setupMatrix();
-    }
-    else
-    {
-      Dune::MatrixIndexSet indices(grid_->size(1), grid_->size(1));
-      assembler_->getNeighborsPerVertex(indices);
-      indices.exportIdx(*hessianMatrix_);
-    }
+
+    auto hessianBackend = Dune::Fufem::istlMatrixBackend(*hessianMatrix_);
+    auto hessianPatternBuilder = hessianBackend.patternBuilder();
+    operatorAssembler.assembleBulkPattern(hessianPatternBuilder);
+    hessianPatternBuilder.setupMatrix();
+
 #if !HAVE_DUNE_PARMG
     innerSolver_ = std::make_shared<LoopSolver<CorrectionType> >(mmgStep,
                                                                    innerIterations_,
diff --git a/dune/elasticity/common/trustregionsolver.hh b/dune/elasticity/common/trustregionsolver.hh
index ca65bde1b302f6d6942bdcaadbc7e286494329ae..fcd49fde53ffc8f71aadc787e16249e111e691ad 100644
--- a/dune/elasticity/common/trustregionsolver.hh
+++ b/dune/elasticity/common/trustregionsolver.hh
@@ -77,10 +77,7 @@ public:
 
     /** \brief Set up the solver using a monotone multigrid method as the inner solver */
     void setup(const GridType& grid,
-               std::conditional_t< // do we have a dune-functions basis? -> choose right assembler type
-                  Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>(),
-                  const Dune::Elasticity::FEAssembler<BasisType,VectorType>*,
-                  const Dune::FEAssembler<DuneFunctionsBasis<BasisType>,VectorType>*> assembler,
+               const Dune::Elasticity::FEAssembler<BasisType,VectorType>* assembler,
                const SolutionType& x,
                const Dune::BitSetVector<blocksize>& dirichletNodes,
                double tolerance,
@@ -146,10 +143,7 @@ protected:
     std::shared_ptr<MatrixType> hessianMatrix_;
 
     /** \brief The assembler for the material law */
-    std::conditional_t< // do we have a dune-functions basis? -> choose right assembler type
-      Dune::models< Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>(),
-        const Dune::Elasticity::FEAssembler<BasisType,VectorType>*,
-        const Dune::FEAssembler<DuneFunctionsBasis<BasisType>,VectorType>* > assembler_;
+    const Dune::Elasticity::FEAssembler<BasisType,VectorType>* assembler_;
 
 #if HAVE_DUNE_PARMG
     /** \brief The solver for the inner problem */
@@ -170,10 +164,10 @@ protected:
     std::shared_ptr<const Dune::BitSetVector<blocksize> > ignoreNodes_;
 
     /** \brief The norm used to measure multigrid convergence */
-    std::shared_ptr< H1SemiNorm<CorrectionType> > h1SemiNorm_;
+    std::shared_ptr<EnergyNorm<MatrixType,CorrectionType> > h1SemiNorm_;
 
     /** \brief An L2-norm, really.  The H1SemiNorm class is badly named */
-    std::shared_ptr<H1SemiNorm<CorrectionType> > l2Norm_;
+    std::shared_ptr<EnergyNorm<MatrixType,CorrectionType> > l2Norm_;
 
 };