diff --git a/example/miniapp/miniapp_recipes.cpp b/example/miniapp/miniapp_recipes.cpp
index 017236d425a05820d39a64debfbb9cb146a46c06..69690387a6b2cc3e10f530a2c32e114665b3a59f 100644
--- a/example/miniapp/miniapp_recipes.cpp
+++ b/example/miniapp/miniapp_recipes.cpp
@@ -176,10 +176,6 @@ public:
         }
     }
 
-    std::vector<event_generator_ptr> event_generators(cell_gid_type) const override {
-        return {};
-    }
-
 protected:
     template <typename RNG>
     cell_connection draw_connection_params(RNG& rng) const {
diff --git a/src/cell.hpp b/src/cell.hpp
index 200691b73bb1d148e09e1755aebe6ce7083f24d3..a4d81592e35864c580662d4b30f43bc522347d30 100644
--- a/src/cell.hpp
+++ b/src/cell.hpp
@@ -54,10 +54,6 @@ struct cell_global_properties {
     std::map<std::string, specialized_mechanism> special_mechs;
 };
 
-// used in constructor below
-struct clone_cell_t {};
-constexpr clone_cell_t clone_cell{};
-
 /// high-level abstract representation of a cell and its segments
 class cell {
 public:
@@ -81,22 +77,25 @@ public:
         double threshold;
     };
 
-    // constructor
+    /// Default constructor
     cell();
 
-    // Sometimes we really do want a copy (pending big morphology refactor).
-    cell(clone_cell_t, const cell& other):
+    /// Copy constructor
+    cell(const cell& other):
         parents_(other.parents_),
         stimuli_(other.stimuli_),
         synapses_(other.synapses_),
         spike_detectors_(other.spike_detectors_)
-     {
-         // unique_ptr's cannot be copy constructed, do a manual assignment
-         segments_.reserve(other.segments_.size());
-         for (const auto& s: other.segments_) {
-             segments_.push_back(s->clone());
-         }
-     }
+    {
+        // unique_ptr's cannot be copy constructed, do a manual assignment
+        segments_.reserve(other.segments_.size());
+        for (const auto& s: other.segments_) {
+            segments_.push_back(s->clone());
+        }
+    }
+
+    /// Move constructor
+    cell(cell&& other) = default;
 
     /// Return the kind of cell, used for grouping into cell_groups
     cell_kind get_cell_kind() const  {
diff --git a/src/common_types.hpp b/src/common_types.hpp
index 2cc3203454943f20691caef3ffa109eaa4948c3d..19a5aacf1c7dfb91a10a1949cf3dd012897c8fda 100644
--- a/src/common_types.hpp
+++ b/src/common_types.hpp
@@ -76,6 +76,7 @@ enum cell_kind {
 } // namespace arb
 
 std::ostream& operator<<(std::ostream& O, arb::cell_member_type m);
+std::ostream& operator<<(std::ostream& O, arb::cell_kind k);
 
 namespace std {
     template <> struct hash<arb::cell_member_type> {
diff --git a/src/common_types_io.cpp b/src/common_types_io.cpp
index 4850d5d8ba0fbe6c437200b2a01ad70728b268c9..9e478115f053a4774c0a26b86bda20182966e986 100644
--- a/src/common_types_io.cpp
+++ b/src/common_types_io.cpp
@@ -6,3 +6,16 @@ std::ostream& operator<<(std::ostream& O, arb::cell_member_type m) {
     return O << m.gid << ':' << m.index;
 }
 
+std::ostream& operator<<(std::ostream& o, arb::cell_kind k) {
+    o << "cell_kind::";
+    switch (k) {
+    case arb::cell_kind::regular_spike_source:
+        return o << "regular_spike_source";
+    case arb::cell_kind::cable1d_neuron:
+        return o << "cable1d_neuron";
+    case arb::cell_kind::data_spike_source:
+        return o << "data_spike_source";
+    }
+    return o;
+}
+
diff --git a/src/fvm_multicell.hpp b/src/fvm_multicell.hpp
index 3eb1fb1a73ebec1b077c5c6d5c484476d0b5e232..aac92841585d74d281c9eec2cd24de8c1fb4a42f 100644
--- a/src/fvm_multicell.hpp
+++ b/src/fvm_multicell.hpp
@@ -638,7 +638,7 @@ void fvm_multicell<Backend>::initialize(
     std::vector<cell> cells;
     cells.reserve(gids.size());
     for (auto gid: gids) {
-        cells.push_back(any_cast<cell>(rec.get_cell_description(gid)));
+        cells.push_back(std::move(any_cast<cell>(rec.get_cell_description(gid))));
     }
 
     auto cell_num_compartments =
diff --git a/src/recipe.hpp b/src/recipe.hpp
index 54ba235d3521a34ce46a7b840883c408384bd202..a8981dbc6191e0ff17f1385b4a4bd17922cbbd5f 100644
--- a/src/recipe.hpp
+++ b/src/recipe.hpp
@@ -60,14 +60,20 @@ public:
     virtual util::unique_any get_cell_description(cell_gid_type gid) const = 0;
     virtual cell_kind get_cell_kind(cell_gid_type) const = 0;
 
-    virtual cell_size_type num_sources(cell_gid_type) const = 0;
-    virtual cell_size_type num_targets(cell_gid_type) const = 0;
-    virtual cell_size_type num_probes(cell_gid_type) const = 0;
+    virtual cell_size_type num_sources(cell_gid_type) const { return 0; }
+    virtual cell_size_type num_targets(cell_gid_type) const { return 0; }
+    virtual cell_size_type num_probes(cell_gid_type)  const { return 0; }
+
+    virtual std::vector<event_generator_ptr> event_generators(cell_gid_type) const {
+        return {};
+    }
+    virtual std::vector<cell_connection> connections_on(cell_gid_type) const {
+        return {};
+    }
+    virtual probe_info get_probe(cell_member_type) const {
+        throw std::logic_error("no probes");
+    }
 
-    virtual std::vector<event_generator_ptr> event_generators(cell_gid_type) const = 0;
-
-    virtual std::vector<cell_connection> connections_on(cell_gid_type) const = 0;
-    virtual probe_info get_probe(cell_member_type probe_id) const = 0;
 
     // Global property type will be specific to given cell kind.
     virtual util::any get_global_properties(cell_kind) const { return util::any{}; };
diff --git a/tests/global_communication/test_communicator.cpp b/tests/global_communication/test_communicator.cpp
index 21d7be0ed1429c7ea2c5716adcf9627f9580ee76..2a5238a47bdba20ec5cb2e3c5c713790c2c765fb 100644
--- a/tests/global_communication/test_communicator.cpp
+++ b/tests/global_communication/test_communicator.cpp
@@ -213,14 +213,6 @@ namespace {
                         1.0f)};     // delay
         }
 
-        std::vector<event_generator_ptr> event_generators(cell_gid_type) const override {
-            return {};
-        }
-
-        probe_info get_probe(cell_member_type) const override {
-            throw std::logic_error("no probes");
-        }
-
     private:
         cell_size_type size_;
         cell_size_type ranks_;
@@ -286,14 +278,6 @@ namespace {
             return cons;
         }
 
-        std::vector<event_generator_ptr> event_generators(cell_gid_type) const override {
-            return {};
-        }
-
-        probe_info get_probe(cell_member_type) const override {
-            throw std::logic_error("no probes");
-        }
-
     private:
         cell_size_type size_;
         cell_size_type ranks_;
diff --git a/tests/global_communication/test_domain_decomposition.cpp b/tests/global_communication/test_domain_decomposition.cpp
index 119dded9f51c4209faaf3f5df44af00bb91278c7..d6cef200ee086c16be70b392dd80e2804e5a5e01 100644
--- a/tests/global_communication/test_domain_decomposition.cpp
+++ b/tests/global_communication/test_domain_decomposition.cpp
@@ -58,9 +58,6 @@ namespace {
             return {};
         }
 
-        probe_info get_probe(cell_member_type) const override {
-            throw std::logic_error("no probes");
-        }
 
     private:
         cell_size_type size_;
diff --git a/tests/simple_recipes.hpp b/tests/simple_recipes.hpp
index 509f6dab90a7e4171b34a70fa47ff7a93e23238f..8e7218c0570d8a5ecd6637270b22a5dd43a50617 100644
--- a/tests/simple_recipes.hpp
+++ b/tests/simple_recipes.hpp
@@ -20,14 +20,6 @@ public:
         return probes_.count(i)? probes_.at(i).size(): 0;
     }
 
-    std::vector<event_generator_ptr> event_generators(cell_gid_type) const override {
-        return {};
-    }
-
-    std::vector<cell_connection> connections_on(cell_gid_type) const override {
-        return {};
-    }
-
     virtual probe_info get_probe(cell_member_type probe_id) const override {
         return probes_.at(probe_id.gid).at(probe_id.index);
     }
@@ -76,9 +68,6 @@ public:
     cell_size_type num_cells() const override { return n_; }
     cell_kind get_cell_kind(cell_gid_type) const override { return Kind; }
 
-    cell_size_type num_sources(cell_gid_type) const override { return 0; }
-    cell_size_type num_targets(cell_gid_type) const override { return 0; }
-
     util::unique_any get_cell_description(cell_gid_type) const override {
         return util::make_unique_any<Description>(desc_);
     }
@@ -98,13 +87,13 @@ public:
     template <typename Seq>
     explicit cable1d_recipe(const Seq& cells) {
         for (const auto& c: cells) {
-            cells_.emplace_back(clone_cell, c);
+            cells_.emplace_back(c);
         }
     }
 
     explicit cable1d_recipe(const cell& c) {
         cells_.reserve(1);
-        cells_.emplace_back(clone_cell, c);
+        cells_.emplace_back(c);
     }
 
     cell_size_type num_cells() const override { return cells_.size(); }
@@ -119,7 +108,7 @@ public:
     }
 
     util::unique_any get_cell_description(cell_gid_type i) const override {
-        return util::make_unique_any<cell>(clone_cell, cells_[i]);
+        return util::make_unique_any<cell>(cells_[i]);
     }
 
 protected:
diff --git a/tests/unit/test_cell.cpp b/tests/unit/test_cell.cpp
index 587f8fa95919b1548c3b9101604c5f8f2bfc68a3..58981bfa626550896e0adfed71bd1d1279bbdca3 100644
--- a/tests/unit/test_cell.cpp
+++ b/tests/unit/test_cell.cpp
@@ -224,7 +224,7 @@ TEST(cell, clone)
 
     // make clone
 
-    cell d(clone_cell, c);
+    cell d(c);
 
     // check equality
 
diff --git a/tests/unit/test_domain_decomposition.cpp b/tests/unit/test_domain_decomposition.cpp
index c6cf69fa02b1f831a3fb33a047fb91a7c0e77979..2bafbf40393af26ac6c12cabf0a9d4769b714d97 100644
--- a/tests/unit/test_domain_decomposition.cpp
+++ b/tests/unit/test_domain_decomposition.cpp
@@ -38,22 +38,6 @@ namespace {
                 cell_kind::cable1d_neuron;
         }
 
-        cell_size_type num_sources(cell_gid_type) const override { return 0; }
-        cell_size_type num_targets(cell_gid_type) const override { return 0; }
-        cell_size_type num_probes(cell_gid_type) const override { return 0; }
-
-        std::vector<cell_connection> connections_on(cell_gid_type) const override {
-            return {};
-        }
-
-        std::vector<event_generator_ptr> event_generators(cell_gid_type) const override {
-            return {};
-        }
-
-        probe_info get_probe(cell_member_type) const override {
-            throw std::logic_error("no probes");
-        }
-
     private:
         cell_size_type size_;
     };
diff --git a/tests/validation/validate_ball_and_stick.cpp b/tests/validation/validate_ball_and_stick.cpp
index b5fd22902d8a4a4ccdf00c828af912ff369fae69..7f8042686a22c15764a6b929d4d1ba601e4cf82c 100644
--- a/tests/validation/validate_ball_and_stick.cpp
+++ b/tests/validation/validate_ball_and_stick.cpp
@@ -2,7 +2,6 @@
 
 #include <cell.hpp>
 #include <common_types.hpp>
-#include <fvm_multicell.hpp>
 #include <load_balance.hpp>
 #include <hardware/node_info.hpp>
 #include <hardware/gpu.hpp>
diff --git a/tests/validation/validate_compartment_policy.cpp b/tests/validation/validate_compartment_policy.cpp
index 75d5ee0d2659c4623caef848427d8d37e6d686f8..c9ee4d3643bf30ec0f41bb7641f1304449d5c3ff 100644
--- a/tests/validation/validate_compartment_policy.cpp
+++ b/tests/validation/validate_compartment_policy.cpp
@@ -5,7 +5,6 @@
 
 #include <common_types.hpp>
 #include <cell.hpp>
-#include <fvm_multicell.hpp>
 #include <model.hpp>
 #include <recipe.hpp>
 #include <simple_sampler.hpp>
diff --git a/tests/validation/validate_kinetic.cpp b/tests/validation/validate_kinetic.cpp
index b0077df1dcddf86d172e9b26e15e2de936a6cfae..83cc8d18eeaa7bbd77d754381ac89aec686d06f5 100644
--- a/tests/validation/validate_kinetic.cpp
+++ b/tests/validation/validate_kinetic.cpp
@@ -4,7 +4,6 @@
 
 #include <common_types.hpp>
 #include <cell.hpp>
-#include <fvm_multicell.hpp>
 #include <hardware/node_info.hpp>
 #include <hardware/gpu.hpp>
 #include <load_balance.hpp>
diff --git a/tests/validation/validate_soma.cpp b/tests/validation/validate_soma.cpp
index 86f8dfd1388dfb8404bb5f69d3177e177f9e06aa..8d0e3e8e5fbae68f40d3f2c252caf9b9d7c2247e 100644
--- a/tests/validation/validate_soma.cpp
+++ b/tests/validation/validate_soma.cpp
@@ -2,7 +2,6 @@
 
 #include <common_types.hpp>
 #include <cell.hpp>
-#include <fvm_multicell.hpp>
 #include <hardware/gpu.hpp>
 #include <hardware/node_info.hpp>
 #include <load_balance.hpp>
diff --git a/tests/validation/validate_synapses.cpp b/tests/validation/validate_synapses.cpp
index 7b611ca90b6d1346e89a7f1bc38a9d6252c24df7..31a7bf3fa022d430df6b52b6fc26288d5db6d281 100644
--- a/tests/validation/validate_synapses.cpp
+++ b/tests/validation/validate_synapses.cpp
@@ -1,6 +1,5 @@
 #include <cell.hpp>
 #include <cell_group.hpp>
-#include <fvm_multicell.hpp>
 #include <hardware/node_info.hpp>
 #include <hardware/gpu.hpp>
 #include <json/json.hpp>