diff --git a/include/caosdb/data_type.h b/include/caosdb/data_type.h
index 42d376698872e086c05a5905484e2f63c11dd346..45d82f01ba952f1c56e8e02178d6721795fbc288 100644
--- a/include/caosdb/data_type.h
+++ b/include/caosdb/data_type.h
@@ -140,6 +140,21 @@ protected:
 
 class DataType : public ScalarProtoMessageWrapper<ProtoDataType> {
 public:
+  /**
+   * Copy constructor.
+   */
+  inline DataType(const DataType &other)
+    : DataType(ProtoMessageWrapper<ProtoDataType>::CopyProtoMessage(other.wrapped)) {}
+
+  /**
+   * Move constructor.
+   */
+  inline DataType(DataType &&other) : DataType(other.wrapped) {
+    other.wrapped = nullptr;
+    other.list_data_type.reset();
+    other.reference_data_type.reset();
+  }
+
   DataType(ProtoDataType *wrapped) : ScalarProtoMessageWrapper<ProtoDataType>(wrapped) {}
   DataType() : ScalarProtoMessageWrapper<ProtoDataType>(static_cast<ProtoDataType *>(nullptr)) {}
   /**
@@ -227,6 +242,37 @@ public:
     return this->wrapped == other.wrapped;
   }
 
+  /**
+   * Copy assignment operator.
+   */
+  inline auto operator=(const DataType &other) -> DataType & {
+    if(this != &other) {
+      this->reference_data_type.reset();
+      this->list_data_type.reset();
+      if(other.wrapped != nullptr) {
+        this->wrapped = ProtoMessageWrapper<ProtoDataType>::CopyProtoMessage(other.wrapped);
+      } else {
+        this->wrapped = nullptr;
+      }
+    }
+    return *this;
+  }
+
+  /**
+   * Move assignment operator.
+   */
+  inline auto operator=(DataType &&other) -> DataType & {
+    if(this != &other) {
+      this->wrapped = other.wrapped;
+      other.wrapped = nullptr;
+      other.reference_data_type.reset();
+      this->reference_data_type.reset();
+      other.list_data_type.reset();
+      this->list_data_type.reset();
+    }
+    return *this;
+  }
+
   friend class Entity;
   friend class Property;
 
diff --git a/include/caosdb/entity.h b/include/caosdb/entity.h
index b31c2c91b9dbb2f41f5b768eca83a64e570e2d5b..c261c1c5af1df71fcf19de377c617092b10deeb0 100644
--- a/include/caosdb/entity.h
+++ b/include/caosdb/entity.h
@@ -187,6 +187,31 @@ public:
     return result.append(std::string("]\n"));
   }
 
+  /**
+   * Return true if the underlying Protobuf messages have the same
+   * serialization.
+   */
+  inline auto operator==(const RepeatedPtrFieldWrapper<T,P> &other) const noexcept -> bool {
+    if (this->wrapped != nullptr && other.wrapped != nullptr && this->size() == other.size()) {
+      for(int i = 0; i < this->size(); i++) {
+        if(this->wrapped->Get(i).SerializeAsString() != other.wrapped->Get(i).SerializeAsString()) {
+          return false;
+        }
+      }
+      return true;
+    }
+    // last chance for "true": both nullptr?
+    return this->wrapped == other.wrapped;
+  }
+
+  /**
+   * Return true if the underlying Protobuf messages have a different
+   * serialization.
+   */
+  inline auto operator!=(const RepeatedPtrFieldWrapper<T,P> &other) const noexcept -> bool {
+    return !(*this == other);
+  }
+
 protected:
   RepeatedPtrFieldWrapper() : ProtoMessageWrapper<RepeatedPtrField<P>>(){};
   explicit inline RepeatedPtrFieldWrapper(RepeatedPtrField<P> *wrapped)
@@ -337,15 +362,13 @@ private:
  */
 class Messages : public RepeatedPtrFieldWrapper<Message, ProtoMessage> {
 public:
-  ~Messages();
-
   friend class Entity;
   // TODO(fspreck) Same here.
   // friend class Parent;
   // friend class Property;
 
 private:
-  inline Messages() : RepeatedPtrFieldWrapper(){};
+  inline Messages() : RepeatedPtrFieldWrapper<Message, ProtoMessage>(){};
 };
 
 /**
@@ -426,14 +449,13 @@ private:
  */
 class Parents : public RepeatedPtrFieldWrapper<Parent, ProtoParent> {
 public:
-  ~Parents() = default;
   friend class Entity;
 
 private:
-  inline Parents() : RepeatedPtrFieldWrapper(){};
+  inline Parents() : RepeatedPtrFieldWrapper<Parent, ProtoParent>(){};
   explicit inline Parents(
     ::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Parent> *wrapped)
-    : RepeatedPtrFieldWrapper(wrapped){};
+    : RepeatedPtrFieldWrapper<Parent, ProtoParent>(wrapped){};
 };
 
 /**
@@ -456,13 +478,10 @@ public:
   /**
    * Move constructor.
    */
-  inline Property(Property &&other) : Property() {
+  inline Property(Property &&other) : Property(other.wrapped) {
     CAOSDB_LOG_TRACE(logger_name) << "Property::Property(Property  &&) "
                                   << "- Move constructor";
-    this->wrapped = std::move(other.wrapped);
-    this->value.wrapped = this->wrapped->mutable_value();
-    this->data_type.wrapped = this->wrapped->mutable_data_type();
-
+    other.wrapped = nullptr;
     other.data_type.wrapped = nullptr;
     other.value.wrapped = nullptr;
   }
@@ -563,8 +582,12 @@ public:
     CAOSDB_LOG_TRACE(logger_name) << "Property::operator=(const Property &) "
                                   << "- Copy assignment operator";
     this->wrapped->CopyFrom(*other.wrapped);
-    this->value = Value(this->wrapped->mutable_value());
-    this->data_type = DataType(this->wrapped->mutable_data_type());
+
+    this->value.wrapped = (this->wrapped->has_value() ? this->wrapped->mutable_value()
+                                                      : static_cast<ProtoValue *>(nullptr));
+    this->data_type.wrapped =
+      (this->wrapped->has_data_type() ? this->wrapped->mutable_data_type()
+                                      : static_cast<ProtoDataType *>(nullptr));
     return *this;
   }
 
@@ -574,7 +597,8 @@ public:
   auto operator=(Property &&other) -> Property & {
     CAOSDB_LOG_TRACE(logger_name) << "Property::operator=(Property &&) "
                                   << "- Move assignment operator";
-    this->wrapped = std::move(other.wrapped);
+    this->wrapped = other.wrapped;
+    other.wrapped = nullptr;
     this->value = std::move(other.value);
     this->data_type = std::move(other.data_type);
     return *this;
@@ -606,7 +630,6 @@ private:
  */
 class Properties : public RepeatedPtrFieldWrapper<Property, ProtoProperty> {
 public:
-  ~Properties() = default;
   friend class Entity;
 
 private:
@@ -677,19 +700,23 @@ public:
   /**
    * Move constructor.
    */
-  explicit inline Entity(Entity &&original) : Entity(std::move(original.wrapped)) {
-    this->properties.wrapped = std::move(original.properties.wrapped);
-    this->parents.wrapped = std::move(original.parents.wrapped);
-    this->errors.wrapped = std::move(original.errors.wrapped);
-    this->warnings.wrapped = std::move(original.warnings.wrapped);
-    this->infos.wrapped = std::move(original.infos.wrapped);
+  explicit inline Entity(Entity &&original) : Entity(original.wrapped) {
+    original.wrapped = nullptr;
+    original.value.wrapped = nullptr;
+    original.data_type.wrapped = nullptr;
+    this->properties = std::move(original.properties);
+    this->parents = std::move(original.parents);
+    this->errors = std::move(original.errors);
+    this->warnings = std::move(original.warnings);
+    this->infos = std::move(original.infos);
   };
 
   /**
    * Move assignment operator.
    */
   auto operator=(Entity &&other) -> Entity & {
-    this->wrapped = std::move(other.wrapped);
+    this->wrapped = other.wrapped;
+    other.wrapped = nullptr;
     this->data_type = std::move(other.data_type);
     this->value = std::move(other.value);
     this->properties = std::move(other.properties);
@@ -706,17 +733,17 @@ public:
    */
   auto operator=(const Entity &other) -> Entity & {
     this->wrapped->CopyFrom(*other.wrapped);
-    this->data_type.wrapped->CopyFrom(*other.data_type.wrapped);
-    this->value.wrapped->CopyFrom(*other.value.wrapped);
-    this->properties.wrapped->CopyFrom(*other.properties.wrapped);
-    this->parents.wrapped->CopyFrom(*other.parents.wrapped);
+    this->data_type = other.data_type;
+    this->value = other.value;
+    this->properties = other.properties;
+    this->parents = other.parents;
     this->file_descriptor.local_path = boost::filesystem::path(other.file_descriptor.local_path);
     this->file_descriptor.file_transmission_id->CopyFrom(
       *other.file_descriptor.file_transmission_id);
     this->file_descriptor.wrapped->CopyFrom(*other.file_descriptor.wrapped);
-    this->errors.wrapped->CopyFrom(*other.errors.wrapped);
-    this->warnings.wrapped->CopyFrom(*other.warnings.wrapped);
-    this->infos.wrapped->CopyFrom(*other.infos.wrapped);
+    this->errors = other.errors;
+    this->warnings = other.warnings;
+    this->infos = other.infos;
     return *this;
   }
 
diff --git a/include/caosdb/protobuf_helper.h b/include/caosdb/protobuf_helper.h
index 4dfc11c396ded34db6bb2cbed2c938a5402dd7c7..63b2c54cdfaae5eef33705ac7074e11c1caf3653 100644
--- a/include/caosdb/protobuf_helper.h
+++ b/include/caosdb/protobuf_helper.h
@@ -70,11 +70,7 @@ public:
    * serialization.
    */
   inline auto operator!=(const ProtoMessageWrapper<P> &other) const noexcept -> bool {
-    if (this->wrapped != nullptr && other.wrapped != nullptr) {
-      return this->wrapped->SerializeAsString() != other.wrapped->SerializeAsString();
-    }
-    // only one is nullptr?
-    return this->wrapped != other.wrapped;
+    return !(*this == other);
   }
 
 protected:
diff --git a/src/caosdb/entity.cpp b/src/caosdb/entity.cpp
index bb73431e4af00ed1db48b8f87fa883db6f4f9b31..a3872e4cb2be380adca644b7c7a109c0fec2b3c2 100644
--- a/src/caosdb/entity.cpp
+++ b/src/caosdb/entity.cpp
@@ -38,8 +38,6 @@ using ProtoFileDescriptor = caosdb::entity::v1alpha1::FileDescriptor;
 using caosdb::utility::get_arena;
 using google::protobuf::Arena;
 
-Messages::~Messages() = default;
-
 // Parent /////////////////////////////////////////////////////////////////////
 
 auto Parent::SetName(const std::string &name) -> void { this->wrapped->set_name(name); }
diff --git a/test/test_entity.cpp b/test/test_entity.cpp
index e456cb4f2d76a06066ec83a7783b1601c30c0415..f800d5a85a878728d73d9bbd23e1d92af99f226f 100644
--- a/test/test_entity.cpp
+++ b/test/test_entity.cpp
@@ -44,7 +44,11 @@ namespace caosdb::entity {
 using caosdb::entity::v1alpha1::IdResponse;
 using ProtoEntity = caosdb::entity::v1alpha1::Entity;
 using ProtoParent = caosdb::entity::v1alpha1::Parent;
+using ProtoProperty = caosdb::entity::v1alpha1::Property;
+using ProtoAtomicDataType = caosdb::entity::v1alpha1::AtomicDataType;
+using caosdb::entity::v1alpha1::EntityResponse;
 using caosdb::utility::get_arena;
+using ProtoEntityRole = caosdb::entity::v1alpha1::EntityRole;
 
 TEST(test_entity, test_parent_setters) {
   auto parent = Parent();
@@ -138,6 +142,121 @@ TEST(test_entity, test_append_property) {
   EXPECT_EQ(prop.GetDataType(), same_prop.GetDataType());
 }
 
+TEST(test_entity, test_copy_constructor) {
+  ProtoParent parent;
+  parent.set_description("the parent desc");
+  parent.set_id("the parent id");
+  parent.set_name("the parent name");
+  ProtoProperty property;
+  property.set_id("the-prop-id");
+  property.set_description("the prop-desc");
+  property.set_name("the-prop-name");
+  property.mutable_value()->mutable_list_values()->mutable_values()->Add()->set_double_value(25.5);
+  property.mutable_data_type()->mutable_list_data_type()->set_atomic_data_type(ProtoAtomicDataType::ATOMIC_DATA_TYPE_DOUBLE);
+  EntityResponse entity_response;
+  entity_response.mutable_entity()->set_id("the-id");
+  entity_response.mutable_entity()->set_name("the-name");
+  entity_response.mutable_entity()->set_role(ProtoEntityRole::ENTITY_ROLE_RECORD);
+  entity_response.mutable_entity()->set_description("the description");
+  entity_response.mutable_entity()->set_unit("the-unit");
+  entity_response.mutable_entity()->mutable_value()->mutable_scalar_value()->set_string_value("the-value");
+  entity_response.mutable_entity()->mutable_version()->set_id("version-id");
+  entity_response.mutable_entity()->mutable_data_type()->mutable_reference_data_type()->set_name("refname");
+  entity_response.mutable_entity()->mutable_file_descriptor();
+  entity_response.mutable_entity()->mutable_properties()->Add()->CopyFrom(property);
+  entity_response.mutable_entity()->mutable_parents()->Add()->CopyFrom(parent);
+
+  Entity this_entity(&entity_response);
+  Entity copy_entity(this_entity);
+
+  EXPECT_EQ(this_entity, copy_entity);
+  EXPECT_EQ(this_entity.GetVersionId(), copy_entity.GetVersionId());
+  EXPECT_EQ(this_entity.GetValue(), copy_entity.GetValue());
+  EXPECT_EQ(this_entity.GetDataType(), copy_entity.GetDataType());
+  EXPECT_EQ(this_entity.GetId(), copy_entity.GetId());
+  EXPECT_EQ(this_entity.GetName(), copy_entity.GetName());
+  EXPECT_EQ(this_entity.GetDescription(), copy_entity.GetDescription());
+  EXPECT_EQ(this_entity.ToString(), copy_entity.ToString());
+  EXPECT_EQ(this_entity.GetErrors().ToString(), copy_entity.GetErrors().ToString());
+  EXPECT_EQ(this_entity.GetWarnings().ToString(), copy_entity.GetWarnings().ToString());
+  EXPECT_EQ(this_entity.GetInfos().ToString(), copy_entity.GetInfos().ToString());
+  EXPECT_EQ(this_entity.GetProperties(), copy_entity.GetProperties());
+
+  // change only description
+  this_entity.SetDescription("new description");
+  EXPECT_NE(this_entity, copy_entity);
+  EXPECT_EQ(this_entity.GetVersionId(), copy_entity.GetVersionId());
+  EXPECT_EQ(this_entity.GetValue(), copy_entity.GetValue());
+  EXPECT_EQ(this_entity.GetDataType(), copy_entity.GetDataType());
+  EXPECT_EQ(this_entity.GetId(), copy_entity.GetId());
+  EXPECT_EQ(this_entity.GetName(), copy_entity.GetName());
+  EXPECT_NE(this_entity.GetDescription(), copy_entity.GetDescription());
+  EXPECT_NE(this_entity.ToString(), copy_entity.ToString());
+}
+
+TEST(test_entity, test_move_constructor) {
+  ProtoParent parent;
+  parent.set_description("the parent desc");
+  parent.set_id("the parent id");
+  parent.set_name("the parent name");
+  ProtoProperty property;
+  property.set_id("the-prop-id");
+  property.set_description("the prop-desc");
+  property.set_name("the-prop-name");
+  property.mutable_value()->mutable_list_values()->mutable_values()->Add()->set_double_value(25.5);
+  property.mutable_data_type()->mutable_list_data_type()->set_atomic_data_type(ProtoAtomicDataType::ATOMIC_DATA_TYPE_DOUBLE);
+  EntityResponse entity_response;
+  entity_response.mutable_errors()->Add()->set_code(25);
+  entity_response.mutable_errors()->Mutable(0)->set_description("asdf");
+  entity_response.mutable_warnings()->Add()->set_code(23);
+  entity_response.mutable_warnings()->Mutable(0)->set_description("asdgsafdg");
+  entity_response.mutable_infos()->Add()->set_code(235);
+  entity_response.mutable_infos()->Mutable(0)->set_description("asdfsad");
+  entity_response.mutable_entity()->set_id("the-id");
+  entity_response.mutable_entity()->set_name("the-name");
+  entity_response.mutable_entity()->set_role(ProtoEntityRole::ENTITY_ROLE_RECORD);
+  entity_response.mutable_entity()->set_description("the description");
+  entity_response.mutable_entity()->set_unit("the-unit");
+  entity_response.mutable_entity()->mutable_value()->mutable_scalar_value()->set_string_value("the-value");
+  entity_response.mutable_entity()->mutable_version()->set_id("version-id");
+  entity_response.mutable_entity()->mutable_data_type()->mutable_reference_data_type()->set_name("refname");
+  entity_response.mutable_entity()->mutable_file_descriptor();
+  entity_response.mutable_entity()->mutable_properties()->Add()->CopyFrom(property);
+  entity_response.mutable_entity()->mutable_parents()->Add()->CopyFrom(parent);
+
+  Entity this_entity(&entity_response);
+  std::string original_string = this_entity.ToString();
+  Entity copy_entity(this_entity);
+  EXPECT_EQ(this_entity, copy_entity);
+
+  Entity move_entity(std::move(this_entity));
+  EXPECT_NE(this_entity, copy_entity); // NOLINT
+
+  EXPECT_EQ(move_entity, copy_entity);
+  EXPECT_EQ(move_entity.GetVersionId(), copy_entity.GetVersionId());
+  EXPECT_EQ(move_entity.GetValue(), copy_entity.GetValue());
+  EXPECT_EQ(move_entity.GetDataType(), copy_entity.GetDataType());
+  EXPECT_EQ(move_entity.GetId(), copy_entity.GetId());
+  EXPECT_EQ(move_entity.GetName(), copy_entity.GetName());
+  EXPECT_EQ(move_entity.GetDescription(), copy_entity.GetDescription());
+  EXPECT_EQ(move_entity.ToString(), copy_entity.ToString());
+  EXPECT_EQ(move_entity.GetErrors().ToString(), copy_entity.GetErrors().ToString());
+  EXPECT_EQ(move_entity.GetWarnings().ToString(), copy_entity.GetWarnings().ToString());
+  EXPECT_EQ(move_entity.GetInfos().ToString(), copy_entity.GetInfos().ToString());
+  EXPECT_EQ(move_entity.GetProperties(), copy_entity.GetProperties());
+
+  // change only description
+  move_entity.SetDescription("new description");
+  EXPECT_NE(move_entity, copy_entity);
+  EXPECT_EQ(move_entity.GetVersionId(), copy_entity.GetVersionId());
+  EXPECT_EQ(move_entity.GetValue(), copy_entity.GetValue());
+  EXPECT_EQ(move_entity.GetDataType(), copy_entity.GetDataType());
+  EXPECT_EQ(move_entity.GetId(), copy_entity.GetId());
+  EXPECT_EQ(move_entity.GetName(), copy_entity.GetName());
+  EXPECT_NE(move_entity.GetDescription(), copy_entity.GetDescription());
+  EXPECT_NE(move_entity.ToString(), copy_entity.ToString());
+}
+
 TEST(test_entity, test_property_copy_constructor) {
   Property prop;
   prop.SetName("prop_name");
@@ -191,15 +310,18 @@ TEST(test_entity, test_property_move_assignment) {
   prop.SetValue("prop_value");
   prop.SetUnit("prop_unit");
   prop.SetDataType("prop_dtype");
+  const auto prop_string = prop.ToString();
 
   // we compare the moved one with this one
   const Property copy_prop(prop);
 
   Property other_prop = std::move(prop);
-  // EXPECT_NE(prop, copy_prop);  NOLINT
-  // EXPECT_NE(prop, other_prop);  NOLINT
-  // EXPECT_EQ(prop.ToString(), "{}"); NOLINT
+  EXPECT_NE(prop, copy_prop);              // NOLINT
+  EXPECT_NE(prop, other_prop);             // NOLINT
+  EXPECT_NE(prop.ToString(), prop_string); // NOLINT
 
+  EXPECT_EQ(copy_prop.ToString(), prop_string);
+  EXPECT_EQ(other_prop.ToString(), prop_string);
   EXPECT_EQ(copy_prop, other_prop);
   EXPECT_EQ(copy_prop.GetName(), other_prop.GetName());
   EXPECT_EQ(copy_prop.GetId(), other_prop.GetId());