diff --git a/arbor/include/arbor/event_generator.hpp b/arbor/include/arbor/event_generator.hpp
index ecd0e476a9dff5bb6367b3b25f1bd5aca59af301..8d12a21817ad54e2579dfea9625d052a3cbea77d 100644
--- a/arbor/include/arbor/event_generator.hpp
+++ b/arbor/include/arbor/event_generator.hpp
@@ -4,6 +4,7 @@
 #include <cstdint>
 #include <memory>
 #include <random>
+#include <type_traits>
 
 #include <arbor/assert.hpp>
 #include <arbor/common_types.hpp>
@@ -61,18 +62,15 @@ using event_seq = std::pair<const spike_event*, const spike_event*>;
 struct empty_generator {
     void reset() {}
     event_seq events(time_type, time_type) {
-        return {&no_event, &no_event};
+        return {nullptr, nullptr};
     }
-
-private:
-    static spike_event no_event;
 };
 
 class event_generator {
 public:
     event_generator(): event_generator(empty_generator()) {}
 
-    template <typename Impl>
+    template <typename Impl, std::enable_if_t<!std::is_same<std::decay_t<Impl>, event_generator>::value, int> = 0>
     event_generator(Impl&& impl):
         impl_(new wrap<Impl>(std::forward<Impl>(impl)))
     {}
@@ -128,6 +126,7 @@ private:
     };
 };
 
+// Convenience routines for making schedule_generator:
 
 // Generate events with a fixed target and weight according to
 // a provided time schedule.
@@ -161,7 +160,7 @@ private:
     schedule sched_;
 };
 
-// Convenience routines for making schedule_generator:
+// Generate events at integer multiples of dt that lie between tstart and tstop.
 
 inline event_generator regular_generator(
     cell_member_type target,
diff --git a/test/unit/test_event_generators.cpp b/test/unit/test_event_generators.cpp
index d79eb42388ae65424fa431e6984e3cd7f786d075..032abda3d88aa9b0795447b1e8e770b74ae9a733 100644
--- a/test/unit/test_event_generators.cpp
+++ b/test/unit/test_event_generators.cpp
@@ -1,5 +1,7 @@
 #include "../gtest.h"
 
+#include <utility>
+
 #include <arbor/event_generator.hpp>
 #include <arbor/spike_event.hpp>
 
@@ -15,8 +17,40 @@ namespace{
     }
 }
 
+TEST(event_generators, assign_and_copy) {
+    event_generator gen = regular_generator({1, 2}, 5., 0.5, 0.75);
+    spike_event expected{{1, 2}, 0.75, 5.};
+
+    auto first = [](const event_seq& seq) {
+        if (seq.first==seq.second) throw std::runtime_error("no events");
+        return *seq.first;
+    };
+
+    ASSERT_EQ(expected, first(gen.events(0., 1.)));
+    gen.reset();
+
+    event_generator g1(gen);
+    EXPECT_EQ(expected, first(g1.events(0., 1.)));
+
+    event_generator g2;
+    g2 = gen;
+    EXPECT_EQ(expected, first(g2.events(0., 1.)));
+
+    const auto& const_gen = gen;
+
+    event_generator g3(const_gen);
+    EXPECT_EQ(expected, first(g3.events(0., 1.)));
+
+    event_generator g4;
+    g4 = gen;
+    EXPECT_EQ(expected, first(g4.events(0., 1.)));
+
+    event_generator g5(std::move(gen));
+    EXPECT_EQ(expected, first(g5.events(0., 1.)));
+}
+
 TEST(event_generators, regular) {
-    // make a regular generator that generates its first event at t=2ms and subsequent
+    // Make a regular generator that generates its first event at t=2ms and subsequent
     // events regularly spaced 0.5 ms apart.
     time_type t0 = 2.0;
     time_type dt = 0.5;
@@ -25,7 +59,7 @@ TEST(event_generators, regular) {
 
     event_generator gen = regular_generator(target, weight, t0, dt);
 
-    // helper for building a set of 
+    // Helper for building a set of expected events.
     auto expected = [&] (std::vector<time_type> times) {
         pse_vector events;
         for (auto t: times) {