diff --git a/include/caosdb/data_type.h b/include/caosdb/data_type.h
index e6b92d53d6ddb1aa8360af55f6438d23eafff7ae..d11f2efd4a1619929ed3a9a602e403d4d642c240 100644
--- a/include/caosdb/data_type.h
+++ b/include/caosdb/data_type.h
@@ -40,6 +40,7 @@ using ProtoReferenceDataType = caosdb::entity::v1alpha1::ReferenceDataType;
 using DataTypeCase = caosdb::entity::v1alpha1::DataType::DataTypeCase;
 using ListDataTypeCase = caosdb::entity::v1alpha1::ListDataType::ListDataTypeCase;
 using caosdb::utility::ProtoMessageWrapper;
+using caosdb::utility::ScalarFieldWrapper;
 
 class Entity;
 class Property;
@@ -68,7 +69,7 @@ const std::map<AtomicDataType, std::string> atomicdatatype_names = {
 class DataType;
 class ListDataType;
 
-class ReferenceDataType : public ProtoMessageWrapper<ProtoDataType> {
+class ReferenceDataType : public ScalarFieldWrapper<ProtoDataType> {
 public:
   [[nodiscard]] inline auto GetName() const noexcept -> const std::string & {
     // is list of reference?
@@ -91,11 +92,11 @@ protected:
   inline static auto Create(ProtoDataType *wrapped) -> std::unique_ptr<ReferenceDataType> {
     return std::unique_ptr<ReferenceDataType>(new ReferenceDataType(wrapped));
   }
-  ReferenceDataType() : ProtoMessageWrapper<ProtoDataType>() {}
-  ReferenceDataType(ProtoDataType *wrapped) : ProtoMessageWrapper<ProtoDataType>(wrapped) {}
+  ReferenceDataType() : ScalarFieldWrapper<ProtoDataType>() {}
+  ReferenceDataType(ProtoDataType *wrapped) : ScalarFieldWrapper<ProtoDataType>(wrapped) {}
 };
 
-class ListDataType : public ProtoMessageWrapper<ProtoDataType> {
+class ListDataType : public ScalarFieldWrapper<ProtoDataType> {
 public:
   [[nodiscard]] inline auto IsListOfReference() const noexcept -> bool {
     return this->wrapped->list_data_type().list_data_type_case() ==
@@ -130,17 +131,17 @@ protected:
   inline static auto Create(ProtoDataType *wrapped) -> std::unique_ptr<ListDataType> {
     return std::unique_ptr<ListDataType>(new ListDataType(wrapped));
   }
-  ListDataType() : ProtoMessageWrapper<ProtoDataType>() {}
+  ListDataType() : ScalarFieldWrapper<ProtoDataType>() {}
 
-  ListDataType(ProtoDataType *wrapped) : ProtoMessageWrapper<ProtoDataType>(wrapped) {}
+  ListDataType(ProtoDataType *wrapped) : ScalarFieldWrapper<ProtoDataType>(wrapped) {}
 
   mutable std::unique_ptr<ReferenceDataType> reference_data_type;
 };
 
-class DataType : public ProtoMessageWrapper<ProtoDataType> {
+class DataType : public ScalarFieldWrapper<ProtoDataType> {
 public:
-  DataType(ProtoDataType *wrapped) : ProtoMessageWrapper<ProtoDataType>(wrapped) {}
-  DataType() : ProtoMessageWrapper<ProtoDataType>() {}
+  DataType(ProtoDataType *wrapped) : ScalarFieldWrapper<ProtoDataType>(wrapped) {}
+  DataType() : ScalarFieldWrapper<ProtoDataType>() {}
   /**
    * Create an AtomicDataType typed DataType.  For references, use the std::string constructor.
    */
diff --git a/include/caosdb/entity.h b/include/caosdb/entity.h
index de6d4928771af83edca68d748d73b58f690a35f7..c066c7e2624afa5b033c9c3795b289238fd8b5f3 100644
--- a/include/caosdb/entity.h
+++ b/include/caosdb/entity.h
@@ -53,6 +53,7 @@
 #include <stdexcept>                                   // for out_of_range
 #include <string>                                      // for string, basic...
 #include <vector>                                      // for vector
+#include <utility>                                     // for move
 
 namespace caosdb::entity {
 using boost::filesystem::exists;
@@ -69,6 +70,7 @@ using caosdb::StatusCode;
 using caosdb::entity::v1alpha1::EntityResponse;
 using caosdb::entity::v1alpha1::FileTransmissionId;
 using caosdb::utility::get_arena;
+using caosdb::utility::ProtoMessageWrapper;
 using ::google::protobuf::RepeatedPtrField;
 using google::protobuf::RepeatedPtrField;
 
@@ -118,14 +120,15 @@ struct FileDescriptor {
  *
  * This is a list-like class.
  */
-template <typename T, typename P> class RepeatedPtrFieldWrapper {
+template <typename T, typename P>
+class RepeatedPtrFieldWrapper : public ProtoMessageWrapper<RepeatedPtrField<P>> {
   class iterator;
 
 public:
   /**
    * Return the current size of the container.
    */
-  [[nodiscard]] inline auto size() const -> int { return wrapped->size(); }
+  [[nodiscard]] inline auto size() const -> int { return this->wrapped->size(); }
   /**
    * Return a const reference to the element at the given index.
    */
@@ -139,10 +142,11 @@ public:
       throw std::out_of_range("Container has size " + std::to_string(size()));
     }
     if (cache.count(index) == 0) {
-      cache.emplace(index, T(&(wrapped->at(index))));
+      cache.emplace(std::move(index), std::move(T(this->wrapped->Mutable(index))));
     }
     return &(cache.at(index));
   }
+
   /**
    * Return iterator positioned at the beginning of the list.
    */
@@ -164,10 +168,26 @@ public:
 
   virtual ~RepeatedPtrFieldWrapper(){};
 
+  inline auto ToString() const noexcept -> const std::string override {
+    if (this->size() == 0) {
+      return "[]";
+    }
+    std::string result("[");
+    for (int i = 0; i < this->size(); i++) {
+      CAOSDB_DEBUG_MESSAGE_STRING(this->wrapped->at(i), next);
+      result += next;
+      if (i < this->size() - 1) {
+        result += ",";
+      }
+    }
+
+    return result.append(std::string("]"));
+  }
+
 protected:
-  RepeatedPtrFieldWrapper(){};
-  explicit inline RepeatedPtrFieldWrapper(::google::protobuf::RepeatedPtrField<P> *wrapped)
-    : wrapped(wrapped){};
+  RepeatedPtrFieldWrapper() : ProtoMessageWrapper<RepeatedPtrField<P>>(){};
+  explicit inline RepeatedPtrFieldWrapper(RepeatedPtrField<P> *wrapped)
+    : ProtoMessageWrapper<RepeatedPtrField<P>>(wrapped) {}
 
   /**
    * Append an element. This adds the element to the end of the wrapped list
@@ -175,13 +195,7 @@ protected:
    */
   inline auto Append(const T &element) -> void {
     auto *destination = this->wrapped->Add();
-    destination->Swap(element.wrapped);
-
-    // Clear the originally wrapped object and return it to the Arena
-    element.wrapped->Clear();
-
-    // set the pointer to the new object which is owned by the RepeatedPtrField
-    element.wrapped = destination;
+    destination->CopyFrom(*element.wrapped);
   }
 
   /**
@@ -189,24 +203,24 @@ protected:
    */
   inline auto Remove(int index) -> void {
     this->wrapped->DeleteSubrange(index, 1);
-    if (cache.count(index) > 0) {
-      cache.erase(index);
-    }
-
-    // shift all indices in the cache above index (such that the values do not
-    // get deleted/copied because this could destroy pointers (c-interface).
-    for (int i = index + 1; i < size(); i++) {
-      if (cache.count(i) > 0) {
-        auto handle = cache.extract(i);
-        handle.key()--;
-        cache.insert(std::move(handle));
-      }
-    }
+    cache.clear();
+    // if (cache.count(index) > 0) {
+    // cache.erase(index);
+    //}
+
+    //// shift all indices in the cache above index (such that the values do not
+    //// get deleted/copied because this could destroy pointers (c-interface).
+    // for (int i = index + 1; i < size(); i++) {
+    // if (cache.count(i) > 0) {
+    // auto handle = cache.extract(i);
+    // handle.key()--;
+    // cache.insert(std::move(handle));
+    //}
+    //}
   }
 
   inline auto Clear() noexcept -> void { this->wrapped->Clear(); }
 
-  ::google::protobuf::RepeatedPtrField<P> *wrapped;
   mutable std::map<int, T> cache;
 
 private:
@@ -282,8 +296,9 @@ auto RepeatedPtrFieldWrapper<T, P>::end() const -> const RepeatedPtrFieldWrapper
  * A Message object can be thought of as kinf of a generalized error object in
  * other frameworks. Please have a look at MessageCodes for more details.
  */
-class Message {
+class Message : public ScalarFieldWrapper<ProtoMessage> {
 public:
+  // inline Message() {};
   /**
    * Get the code of this message.
    *
@@ -310,9 +325,7 @@ public:
   friend class RepeatedPtrFieldWrapper<Message, ProtoMessage>;
 
 private:
-  explicit inline Message(ProtoMessage *wrapped) : wrapped(wrapped){};
-
-  ProtoMessage *wrapped;
+  explicit inline Message(ProtoMessage *wrapped) : ScalarFieldWrapper<ProtoMessage>(wrapped){};
 };
 
 /**
@@ -338,10 +351,10 @@ private:
  * words, this class wraps a protobuf message and provides getter and setter
  * methods.
  */
-class Parent {
+class Parent : public ScalarFieldWrapper<ProtoParent> {
 public:
-  explicit inline Parent(ProtoParent *wrapped) : wrapped(wrapped){};
-  Parent();
+  explicit inline Parent(ProtoParent *wrapped) : ScalarFieldWrapper<ProtoParent>(wrapped){};
+  Parent() : ScalarFieldWrapper<ProtoParent>(){};
 
   /**
    * Return the id of the parent entity.
@@ -365,19 +378,6 @@ public:
    */
   auto SetName(const std::string &name) -> void;
 
-  /**
-   * Return a json string representing this parent.
-   *
-   * This is intended for debugging.
-   */
-  inline auto ToString() const -> const std::string {
-    google::protobuf::util::JsonPrintOptions options;
-    options.add_whitespace = true;
-    std::string out;
-    google::protobuf::util::MessageToJsonString(*(this->wrapped), &out, options);
-    return out;
-  }
-
   // TODO(fspreck) Finish the following implementations once we have
   // decided how to attach messages to parents.
   // /**
@@ -410,22 +410,6 @@ public:
   friend class RepeatedPtrFieldWrapper<Parent, ProtoParent>;
 
 private:
-  /**
-   * Return an empty protobuf message pointer.
-   *
-   * This function is called by the default constructor of the
-   * caosdb::entity::Parent class and the protobuf message is used as the
-   * storage-backend for the new Parent instance.
-   *
-   * An 'Arena' takes care of the the memory management. Don't try to delete
-   * this.
-   */
-  static auto CreateProtoParent() -> ProtoParent *;
-
-  /**
-   * Message which serves as storage backend.
-   */
-  mutable ProtoParent *wrapped;
   // Messages errors;
   // Messages warnings;
   // Messages infos;
@@ -454,12 +438,37 @@ private:
  * This is a property which belongs to another entity. Don't confuse it with
  * an Entity with the "Property" role.
  */
-class Property {
+class Property : public ScalarFieldWrapper<ProtoProperty> {
 public:
+  /**
+   * Copy constructor.
+   */
+  inline Property(const Property &other)
+    : Property(ProtoMessageWrapper<ProtoProperty>::CopyProtoMessage(other.wrapped)) {
+    CAOSDB_LOG_TRACE(logger_name) << "Property::Property(const Property &) "
+                                  << "- Copy constructor";
+  };
+
+  /**
+   * Move constructor.
+   */
+  inline Property(Property &&other) : Property() {
+    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.data_type.wrapped = nullptr;
+    other.value.wrapped = nullptr;
+  }
+
   explicit inline Property(ProtoProperty *other)
-    : value(Value(other->mutable_value())), data_type(DataType(other->mutable_data_type())),
-      wrapped(other){};
-  Property();
+    : ScalarFieldWrapper<ProtoProperty>(other), value(this->wrapped->mutable_value()),
+      data_type(this->wrapped->mutable_data_type()){};
+  inline Property()
+    : ScalarFieldWrapper<ProtoProperty>(), value(this->wrapped->mutable_value()),
+      data_type(this->wrapped->mutable_data_type()){};
 
   /**
    * Return the id of this  property
@@ -541,16 +550,27 @@ public:
   auto SetDataType(const std::string &new_data_type, bool list_type = false) -> StatusCode;
 
   /**
-   * Return a json string representing this property.
-   *
-   * This is intended for debugging
+   * Copy assignment operator.
    */
-  inline auto ToString() const -> const std::string {
-    google::protobuf::util::JsonPrintOptions options;
-    options.add_whitespace = true;
-    std::string out;
-    google::protobuf::util::MessageToJsonString(*(this->wrapped), &out, options);
-    return out;
+  auto operator=(const Property &other) -> Property & {
+    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());
+    return *this;
+  }
+
+  /**
+   * Move assignment operator.
+   */
+  auto operator=(Property &&other) -> Property & {
+    CAOSDB_LOG_TRACE(logger_name) << "Property::operator=(Property &&) "
+                                  << "- Move assignment operator";
+    this->wrapped = std::move(other.wrapped);
+    this->value = std::move(other.value);
+    this->data_type = std::move(other.data_type);
+    return *this;
   }
 
   friend class Entity;
@@ -558,11 +578,8 @@ public:
   friend class RepeatedPtrFieldWrapper<Property, ProtoProperty>;
 
 private:
-  static auto CreateProtoProperty() -> ProtoProperty *;
   Value value;
   DataType data_type;
-
-  mutable ProtoProperty *wrapped;
 };
 
 /**
@@ -580,16 +597,15 @@ private:
  * for (auto &property : my_properties) {...}
  * \endcode
  */
-class Properties : public RepeatedPtrFieldWrapper<Property, caosdb::entity::v1alpha1::Property> {
+class Properties : public RepeatedPtrFieldWrapper<Property, ProtoProperty> {
 public:
   ~Properties() = default;
   friend class Entity;
 
 private:
   inline Properties(){};
-  explicit inline Properties(
-    ::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Property> *wrapped)
-    : RepeatedPtrFieldWrapper<Property, caosdb::entity::v1alpha1::Property>(wrapped){};
+  explicit inline Properties(RepeatedPtrField<ProtoProperty> *wrapped)
+    : RepeatedPtrFieldWrapper<Property, ProtoProperty>(wrapped){};
 };
 
 /**
diff --git a/include/caosdb/protobuf_helper.h b/include/caosdb/protobuf_helper.h
index 9a73c0d726b25a792232530d0e01852d9c0b2e99..4e0114ab4f71e64f14c0693704351487deec8dca 100644
--- a/include/caosdb/protobuf_helper.h
+++ b/include/caosdb/protobuf_helper.h
@@ -22,16 +22,17 @@
 #ifndef CAOSDB_PROTOBUF_HELPER_H
 #define CAOSDB_PROTOBUF_HELPER_H
 
-#include "caosdb/status_code.h"             // for StatusCode, SUCCESS
-#include <google/protobuf/arena.h>          // for Arena
-#include <google/protobuf/extension_set.h>  // for Arena
-#include <google/protobuf/util/json_util.h> // for JsonOptions, MessageToJs...
-#include <string>                           // for string
+#include "caosdb/status_code.h"                     // for StatusCode, SUCCESS
+#include <google/protobuf/arena.h>                  // for Arena
+#include <google/protobuf/generated_message_util.h> // for Arena
+#include <google/protobuf/util/json_util.h>         // for JsonOptions, MessageToJs...
+#include <string>                                   // for string
 
 #define CAOSDB_DEBUG_MESSAGE_STRING(message, out)                                                  \
   std::string out;                                                                                 \
   {                                                                                                \
     google::protobuf::util::JsonOptions options;                                                   \
+    options.add_whitespace = true;                                                                 \
     google::protobuf::util::MessageToJsonString(message, &out, options);                           \
   }
 
@@ -43,8 +44,8 @@ auto get_arena() -> Arena *;
 
 template <typename P> class ProtoMessageWrapper {
 public:
-  ProtoMessageWrapper(const ProtoMessageWrapper &other) = default;
-  inline auto CopyFrom(const ProtoMessageWrapper &other) noexcept -> StatusCode {
+  ProtoMessageWrapper(const ProtoMessageWrapper<P> &other) = default;
+  inline auto CopyFrom(const ProtoMessageWrapper<P> &other) noexcept -> StatusCode {
     this->wrapped->CopyFrom(*other.wrapped);
     return StatusCode::SUCCESS;
   }
@@ -52,16 +53,51 @@ public:
   /**
    * Return a json representation of this object.
    */
-  inline auto ToString() const noexcept -> const std::string {
-    CAOSDB_DEBUG_MESSAGE_STRING(*wrapped, out)
-    return out;
+  virtual inline auto ToString() const noexcept -> const std::string = 0;
+  //{
+  // CAOSDB_DEBUG_MESSAGE_STRING(*wrapped, out)
+  // return out;
+  //}
+
+  /**
+   * Return true if the underlying Protobuf messages have the same
+   * serialization.
+   */
+  inline auto operator==(const ProtoMessageWrapper<P> &other) const noexcept -> bool {
+    return this->wrapped->SerializeAsString() == other.wrapped->SerializeAsString();
+  }
+
+  /**
+   * Return true if the underlying Protobuf messages have a different
+   * serialization.
+   */
+  inline auto operator!=(const ProtoMessageWrapper<P> &other) const noexcept -> bool {
+    return this->wrapped->SerializeAsString() != other.wrapped->SerializeAsString();
   }
 
 protected:
+  inline static auto CopyProtoMessage(P *wrapped) -> P * {
+    P *copy = Arena::CreateMessage<P>(get_arena());
+    copy->CopyFrom(*wrapped);
+    return copy;
+  }
   ProtoMessageWrapper() : ProtoMessageWrapper(Arena::CreateMessage<P>(get_arena())) {}
   ProtoMessageWrapper(P *wrapped) : wrapped(wrapped) {}
   P *wrapped;
 };
 
+template <typename P> class ScalarFieldWrapper : public ProtoMessageWrapper<P> {
+public:
+  inline ScalarFieldWrapper() = default;
+  inline ScalarFieldWrapper(P *wrapped) : ProtoMessageWrapper<P>(wrapped) {}
+  /**
+   * Return a json representation of this object.
+   */
+  inline auto ToString() const noexcept -> const std::string override {
+    CAOSDB_DEBUG_MESSAGE_STRING(*this->wrapped, out)
+    return out;
+  }
+};
+
 } // namespace caosdb::utility
 #endif
diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h
index 0699e14b28ae6e4b44ff495695c843ffa2e8d01f..68040dc663a378e58840281acfd3f8a659881bc8 100644
--- a/include/caosdb/transaction.h
+++ b/include/caosdb/transaction.h
@@ -35,7 +35,6 @@
 #include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_E...
 #include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_S...
 #include <google/protobuf/arena.h>                    // for Arena
-#include <google/protobuf/generated_message_util.h>   // for CreateMessage...
 #include <google/protobuf/util/json_util.h>           // for MessageToJsonS...
 #include <grpcpp/impl/codegen/completion_queue.h>     // for CompletionQueue
 #include <algorithm>                                  // for max
diff --git a/include/caosdb/value.h b/include/caosdb/value.h
index fd70c4f837dccaeedca0c9801c2518eb111af398..f4f8f3b91851070818a85d6272eb0c16f5748a8a 100644
--- a/include/caosdb/value.h
+++ b/include/caosdb/value.h
@@ -31,7 +31,7 @@
 #include <vector>                           // for vector
 
 #define LIST_VALUE_CONSTRUCTOR(TYPE, SETTER)                                                       \
-  explicit inline Value(const std::vector<TYPE> &values) : ProtoMessageWrapper<ProtoValue>() {     \
+  explicit inline Value(const std::vector<TYPE> &values) : ScalarFieldWrapper<ProtoValue>() {      \
     for (const auto &value : values) {                                                             \
       this->wrapped->mutable_list_values()->add_values()->SETTER(value);                           \
     }                                                                                              \
@@ -40,6 +40,7 @@
 namespace caosdb::entity {
 using caosdb::utility::get_arena;
 using caosdb::utility::ProtoMessageWrapper;
+using caosdb::utility::ScalarFieldWrapper;
 using google::protobuf::Arena;
 using ProtoSpecialValue = caosdb::entity::v1alpha1::SpecialValue;
 using ProtoValue = caosdb::entity::v1alpha1::Value;
@@ -167,7 +168,7 @@ protected:
 
 inline AbstractValue::~AbstractValue() {}
 
-class ScalarValue : public AbstractValue, public ProtoMessageWrapper<ProtoScalarValue> {
+class ScalarValue : public AbstractValue, public ScalarFieldWrapper<ProtoScalarValue> {
 public:
   /**
    * Destructor.
@@ -203,7 +204,7 @@ public:
   }
 
   inline ScalarValue(ProtoScalarValue *wrapped)
-    : ProtoMessageWrapper<ProtoScalarValue>(wrapped), proto_value(nullptr) {}
+    : ScalarFieldWrapper<ProtoScalarValue>(wrapped), proto_value(nullptr) {}
 
   [[nodiscard]] inline auto IsNull() const noexcept -> bool {
     return (this->wrapped->scalar_value_case() == ScalarValueCase::kSpecialValue &&
@@ -248,7 +249,7 @@ public:
     return empty_collection;
   }
   [[nodiscard]] inline auto ToString() const noexcept -> const std::string {
-    return ProtoMessageWrapper::ToString();
+    return ScalarFieldWrapper::ToString();
   }
 
   friend class Value;
@@ -261,13 +262,13 @@ protected:
     }
     return this->proto_value;
   };
-  inline ScalarValue() : ProtoMessageWrapper<ProtoScalarValue>(), proto_value(nullptr) {}
+  inline ScalarValue() : ScalarFieldWrapper<ProtoScalarValue>(), proto_value(nullptr) {}
 
 private:
   mutable ProtoValue *proto_value;
 };
 
-class Value : public AbstractValue, public ProtoMessageWrapper<ProtoValue> {
+class Value : public AbstractValue, public ScalarFieldWrapper<ProtoValue> {
 public:
   /**
    * Copy constructor.
@@ -281,7 +282,7 @@ public:
    * Destructor.
    */
   inline ~Value() {}
-  inline Value() : ProtoMessageWrapper<ProtoValue>() {
+  inline Value() : ScalarFieldWrapper<ProtoValue>() {
     // has NULL_VALUE now
   }
   explicit inline Value(const ScalarValue &value) : Value() {
@@ -290,21 +291,21 @@ public:
   explicit inline Value(const AbstractValue &value) : Value() {
     this->wrapped->CopyFrom(*value.GetProtoValue());
   }
-  explicit inline Value(ProtoValue *wrapped) : ProtoMessageWrapper<ProtoValue>(wrapped) {}
-  explicit inline Value(const std::string &value) : ProtoMessageWrapper<ProtoValue>() {
+  explicit inline Value(ProtoValue *wrapped) : ScalarFieldWrapper<ProtoValue>(wrapped) {}
+  explicit inline Value(const std::string &value) : ScalarFieldWrapper<ProtoValue>() {
     this->wrapped->mutable_scalar_value()->set_string_value(value);
   }
-  explicit inline Value(const char *value) : ProtoMessageWrapper<ProtoValue>() {
+  explicit inline Value(const char *value) : ScalarFieldWrapper<ProtoValue>() {
     this->wrapped->mutable_scalar_value()->set_string_value(std::string(value));
   }
-  explicit inline Value(double value) : ProtoMessageWrapper<ProtoValue>() {
+  explicit inline Value(double value) : ScalarFieldWrapper<ProtoValue>() {
     this->wrapped->mutable_scalar_value()->set_double_value(value);
   }
-  explicit inline Value(int64_t value) : ProtoMessageWrapper<ProtoValue>() {
+  explicit inline Value(int64_t value) : ScalarFieldWrapper<ProtoValue>() {
     this->wrapped->mutable_scalar_value()->set_integer_value(value);
   }
   explicit inline Value(int value) : Value(static_cast<int64_t>(value)) {}
-  explicit inline Value(bool value) : ProtoMessageWrapper<ProtoValue>() {
+  explicit inline Value(bool value) : ScalarFieldWrapper<ProtoValue>() {
     this->wrapped->mutable_scalar_value()->set_boolean_value(value);
   }
 
@@ -387,14 +388,6 @@ public:
     return *(this->collection_values);
   }
 
-  /**
-   * Return true if the underlying Protobuf messages have the same
-   * serialization.
-   */
-  inline auto operator==(const Value &other) const noexcept -> bool {
-    return this->wrapped->SerializeAsString() == other.wrapped->SerializeAsString();
-  }
-
   /**
    * Copy assignment operator.
    */
@@ -416,7 +409,7 @@ public:
   }
 
   [[nodiscard]] inline auto ToString() const noexcept -> const std::string {
-    return ProtoMessageWrapper::ToString();
+    return ScalarFieldWrapper::ToString();
   }
 
   friend class Entity;
diff --git a/src/caosdb/entity.cpp b/src/caosdb/entity.cpp
index c409a46e8ad37aee93b67b2a36109b1fe8f8c640..37d7b3ce6ebdb11d8e0ce7cf8f2a03c1c090c3f6 100644
--- a/src/caosdb/entity.cpp
+++ b/src/caosdb/entity.cpp
@@ -42,18 +42,6 @@ Messages::~Messages() = default;
 
 // Parent /////////////////////////////////////////////////////////////////////
 
-Parent::Parent() : wrapped(Parent::CreateProtoParent()) {
-  // TODO(fspreck) Re-enable once we have decided how to attach
-  // messages to parents.
-  // errors.wrapped = this->wrapped->mutable_errors();
-  // warnings.wrapped = this->wrapped->mutable_warnings();
-  // infos.wrapped = this->wrapped->mutable_infos();
-}
-
-auto Parent::CreateProtoParent() -> ProtoParent * {
-  return Arena::CreateMessage<ProtoParent>(get_arena());
-}
-
 auto Parent::SetName(const std::string &name) -> void { this->wrapped->set_name(name); }
 
 auto Parent::SetId(const std::string &id) -> void { this->wrapped->set_id(id); }
@@ -66,11 +54,7 @@ auto Parent::SetId(const std::string &id) -> void { this->wrapped->set_id(id); }
   return this->wrapped->description();
 }
 
-Property::Property() : Property(Property::CreateProtoProperty()) {}
-
-auto Property::CreateProtoProperty() -> ProtoProperty * {
-  return Arena::CreateMessage<ProtoProperty>(get_arena());
-}
+// Property ///////////////////////////////////////////////////////////////////
 
 [[nodiscard]] auto Property::GetId() const -> const std::string & { return this->wrapped->id(); }
 
diff --git a/src/caosdb/file_transmission/download_request_handler.cpp b/src/caosdb/file_transmission/download_request_handler.cpp
index a157754b337e798fc4c144cb44abea153053ed79..cbe79e93eb89261d1d85484cf39f4ad5deecba18 100644
--- a/src/caosdb/file_transmission/download_request_handler.cpp
+++ b/src/caosdb/file_transmission/download_request_handler.cpp
@@ -59,17 +59,16 @@
 #include <boost/preprocessor/seq/limits/size_256.hpp>  // for BOOST_PP_SEQ_...
 #include <exception>                                   // IWYU pragma: keep
 // IWYU pragma: no_include <bits/exception.h>
-#include <google/protobuf/arena.h>                  // for Arena
-#include <google/protobuf/generated_message_util.h> // for Arena
-#include <grpcpp/impl/codegen/async_stream.h>       // for ClientAsyncRe...
-#include <grpcpp/impl/codegen/client_context.h>     // for ClientContext
-#include <grpcpp/impl/codegen/completion_queue.h>   // for CompletionQueue
-#include <grpcpp/impl/codegen/status.h>             // for Status
-#include <grpcpp/impl/codegen/status_code_enum.h>   // for OK, UNAUTHENT...
-#include <iostream>                                 // for char_traits
-#include <stdexcept>                                // for runtime_error
-#include <string>                                   // for string, opera...
-#include <utility>                                  // for move
+#include <google/protobuf/arena.h>                // for Arena
+#include <grpcpp/impl/codegen/async_stream.h>     // for ClientAsyncRe...
+#include <grpcpp/impl/codegen/client_context.h>   // for ClientContext
+#include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue
+#include <grpcpp/impl/codegen/status.h>           // for Status
+#include <grpcpp/impl/codegen/status_code_enum.h> // for OK, UNAUTHENT...
+#include <iostream>                               // for char_traits
+#include <stdexcept>                              // for runtime_error
+#include <string>                                 // for string, opera...
+#include <utility>                                // for move
 
 namespace caosdb::transaction {
 using caosdb::StatusCode;
diff --git a/src/caosdb/file_transmission/upload_request_handler.cpp b/src/caosdb/file_transmission/upload_request_handler.cpp
index cc8170249b932fb8bfa572fd345746bbbacc16af..bc74391753a0c7c3dce01f80d8fa67acc9e782cd 100644
--- a/src/caosdb/file_transmission/upload_request_handler.cpp
+++ b/src/caosdb/file_transmission/upload_request_handler.cpp
@@ -61,17 +61,16 @@
 #include <cstdint>                                     // for uint64_t
 #include <exception>                                   // IWYU pragma: keep
 // IWYU pragma: no_include <bits/exception.h>
-#include <google/protobuf/arena.h>                  // for Arena
-#include <google/protobuf/generated_message_util.h> // for CreateMessage...
-#include <grpcpp/impl/codegen/async_stream.h>       // for ClientAsyncWr...
-#include <grpcpp/impl/codegen/call_op_set.h>        // for WriteOptions
-#include <grpcpp/impl/codegen/client_context.h>     // for ClientContext
-#include <grpcpp/impl/codegen/completion_queue.h>   // for CompletionQueue
-#include <grpcpp/impl/codegen/status.h>             // for Status
-#include <grpcpp/impl/codegen/status_code_enum.h>   // for OK, UNAUTHENT...
-#include <iostream>                                 // for endl, streamsize
-#include <string>                                   // for basic_string
-#include <utility>                                  // for move
+#include <google/protobuf/arena.h>                // for Arena
+#include <grpcpp/impl/codegen/async_stream.h>     // for ClientAsyncWr...
+#include <grpcpp/impl/codegen/call_op_set.h>      // for WriteOptions
+#include <grpcpp/impl/codegen/client_context.h>   // for ClientContext
+#include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue
+#include <grpcpp/impl/codegen/status.h>           // for Status
+#include <grpcpp/impl/codegen/status_code_enum.h> // for OK, UNAUTHENT...
+#include <iostream>                               // for endl, streamsize
+#include <string>                                 // for basic_string
+#include <utility>                                // for move
 
 namespace caosdb::transaction {
 using caosdb::StatusCode;
diff --git a/src/caosdb/protobuf_helper.cpp b/src/caosdb/protobuf_helper.cpp
index e8bbd07834ead9b561c7e8769ed834527337f7a6..418d14b9c847bc204582f6165fae81bf6adcc156 100644
--- a/src/caosdb/protobuf_helper.cpp
+++ b/src/caosdb/protobuf_helper.cpp
@@ -19,8 +19,7 @@
  *
  */
 #include "caosdb/protobuf_helper.h"
-#include <google/protobuf/arena.h>         // for Arena
-#include <google/protobuf/extension_set.h> // for Arena
+#include <google/protobuf/arena.h> // for Arena
 
 namespace caosdb::utility {
 
diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp
index 551d90560498a2aee4b3ce169d416079e8cc80c0..6380dcdde6f845ae4507328d5ccb073d82942b06 100644
--- a/src/caosdb/transaction.cpp
+++ b/src/caosdb/transaction.cpp
@@ -35,15 +35,14 @@
 #include <boost/preprocessor/seq/limits/enum_256.hpp>              // for BOOST_PP_SEQ_...
 #include <boost/preprocessor/seq/limits/size_256.hpp>              // for BOOST_PP_SEQ_...
 // IWYU pragma: no_include <bits/exception.h>
-#include <exception>                                // IWYU pragma: keep
-#include <google/protobuf/arena.h>                  // for Arena
-#include <google/protobuf/generated_message_util.h> // for CreateMessage...
-#include <grpc/impl/codegen/gpr_types.h>            // for gpr_timespec
-#include <grpcpp/impl/codegen/completion_queue.h>   // for CompletionQueue
-#include <iosfwd>                                   // for streamsize
-#include <map>                                      // for map, operator!=
-#include <memory>                                   // for unique_ptr
-#include <utility>                                  // for move, pair
+#include <exception>                              // IWYU pragma: keep
+#include <google/protobuf/arena.h>                // for Arena
+#include <grpc/impl/codegen/gpr_types.h>          // for gpr_timespec
+#include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue
+#include <iosfwd>                                 // for streamsize
+#include <map>                                    // for map, operator!=
+#include <memory>                                 // for unique_ptr
+#include <utility>                                // for move, pair
 
 namespace caosdb::transaction {
 using caosdb::entity::v1alpha1::EntityTransactionService;
diff --git a/test/test_entity.cpp b/test/test_entity.cpp
index 75adc7e7a051cc1e2a154d6b3723e44123e28130..d4b67705bf88e5f425f270692f160e5a6cb84ac0 100644
--- a/test/test_entity.cpp
+++ b/test/test_entity.cpp
@@ -38,6 +38,7 @@
 #include <memory>                                // for allocator, shared_ptr
 #include <stdexcept>                             // for out_of_range
 #include <string>                                // for operator+, to_string
+#include <utility>                               // for move
 
 namespace caosdb::entity {
 using caosdb::entity::v1alpha1::IdResponse;
@@ -132,11 +133,88 @@ TEST(test_entity, test_append_property) {
   EXPECT_EQ(prop.GetName(), same_prop.GetName());
   EXPECT_EQ(prop.GetId(), same_prop.GetId());
   EXPECT_EQ(prop.GetImportance(), same_prop.GetImportance());
-  EXPECT_EQ(prop.GetValue(), same_prop.GetValue());
+  EXPECT_EQ(prop.GetValue().ToString(), same_prop.GetValue().ToString());
   EXPECT_EQ(prop.GetUnit(), same_prop.GetUnit());
   EXPECT_EQ(prop.GetDataType(), same_prop.GetDataType());
 }
 
+TEST(test_entity, test_property_copy_constructor) {
+  Property prop;
+  prop.SetName("prop_name");
+  prop.SetId("prop_id");
+  prop.SetImportance(Importance::RECOMMENDED);
+  prop.SetValue("prop_value");
+  prop.SetUnit("prop_unit");
+  prop.SetDataType("prop_dtype");
+
+  Property other_prop(prop);
+
+  EXPECT_EQ(prop, other_prop);
+  EXPECT_EQ(prop.GetName(), other_prop.GetName());
+  EXPECT_EQ(prop.GetId(), other_prop.GetId());
+  EXPECT_EQ(prop.GetImportance(), other_prop.GetImportance());
+  EXPECT_EQ(prop.GetValue().ToString(), other_prop.GetValue().ToString());
+  EXPECT_EQ(prop.GetUnit(), other_prop.GetUnit());
+  EXPECT_EQ(prop.GetDataType(), other_prop.GetDataType());
+}
+
+TEST(test_entity, test_property_copy_assignment) {
+  Property prop;
+  prop.SetName("prop_name");
+  prop.SetId("prop_id");
+  prop.SetImportance(Importance::RECOMMENDED);
+  prop.SetValue("prop_value");
+  prop.SetUnit("prop_unit");
+  prop.SetDataType("prop_dtype");
+
+  auto other_prop = prop;
+  EXPECT_EQ(prop, other_prop);
+  EXPECT_EQ(prop.GetName(), other_prop.GetName());
+  EXPECT_EQ(prop.GetId(), other_prop.GetId());
+  EXPECT_EQ(prop.GetImportance(), other_prop.GetImportance());
+  EXPECT_EQ(prop.GetValue().ToString(), other_prop.GetValue().ToString());
+  EXPECT_EQ(prop.GetUnit(), other_prop.GetUnit());
+  EXPECT_EQ(prop.GetDataType(), other_prop.GetDataType());
+
+  other_prop.SetName("other_prop_name");
+  EXPECT_NE(prop, other_prop);
+  EXPECT_NE(prop.GetName(), other_prop.GetName());
+  EXPECT_EQ(prop.GetName(), "prop_name");
+  EXPECT_EQ(other_prop.GetName(), "other_prop_name");
+}
+
+TEST(test_entity, test_property_move_assignment) {
+  Property prop;
+  prop.SetName("prop_name");
+  prop.SetId("prop_id");
+  prop.SetImportance(Importance::RECOMMENDED);
+  prop.SetValue("prop_value");
+  prop.SetUnit("prop_unit");
+  prop.SetDataType("prop_dtype");
+
+  // 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_EQ(copy_prop, other_prop);
+  EXPECT_EQ(copy_prop.GetName(), other_prop.GetName());
+  EXPECT_EQ(copy_prop.GetId(), other_prop.GetId());
+  EXPECT_EQ(copy_prop.GetImportance(), other_prop.GetImportance());
+  EXPECT_EQ(copy_prop.GetValue().ToString(), other_prop.GetValue().ToString());
+  EXPECT_EQ(copy_prop.GetUnit(), other_prop.GetUnit());
+  EXPECT_EQ(copy_prop.GetDataType(), other_prop.GetDataType());
+
+  other_prop.SetName("other_prop_name");
+  EXPECT_NE(copy_prop, other_prop);
+  EXPECT_NE(copy_prop.GetName(), other_prop.GetName());
+  EXPECT_EQ(copy_prop.GetName(), "prop_name");
+  EXPECT_EQ(other_prop.GetName(), "other_prop_name");
+}
+
 TEST(test_entity, test_copy_to) {
   auto entity = Entity();
   entity.SetRole(Role::RECORD);
@@ -361,7 +439,22 @@ TEST(test_entity, test_remove_property) {
   // P0,P1,P2,P3,P4,P5,P6,P7,P8,P9
   //          ^
   // P0,P1,P2,   P4,P5,P6,P7,P8,P9
+  CAOSDB_LOG_WARN(logger_name) << "REMOVE(3)!!!!!!!!!!!!!!!!!!!!!";
+  CAOSDB_LOG_WARN(logger_name) << entity.GetProperties().ToString();
   entity.RemoveProperty(3);
+  CAOSDB_LOG_WARN(logger_name) << entity.GetProperties().ToString();
+
+  ASSERT_EQ(entity.GetProperties().size(), 9);
+  for (int i = 0; i < 3; i++) {
+    auto name = "PROPERTY-" + std::to_string(i);
+    const auto &property = entity.GetProperties().at(i);
+    EXPECT_EQ(property.GetName(), name);
+  }
+  for (int i = 3; i < 9; i++) {
+    auto name = "PROPERTY-" + std::to_string(i + 1);
+    const auto &property = entity.GetProperties().at(i);
+    EXPECT_EQ(property.GetName(), name);
+  }
 
   // Remove at index 6
   // P0,P1,P2,   P4,P5,P6,P7,P8,P9
@@ -369,6 +462,21 @@ TEST(test_entity, test_remove_property) {
   // P0,P1,P2,   P4,P5,P6,   P8,P9
   entity.RemoveProperty(6);
   ASSERT_EQ(entity.GetProperties().size(), 8);
+  for (int i = 0; i < 3; i++) {
+    auto name = "PROPERTY-" + std::to_string(i);
+    const auto &property = entity.GetProperties().at(i);
+    EXPECT_EQ(property.GetName(), name);
+  }
+  for (int i = 3; i < 6; i++) {
+    auto name = "PROPERTY-" + std::to_string(i + 1);
+    const auto &property = entity.GetProperties().at(i);
+    EXPECT_EQ(property.GetName(), name);
+  }
+  for (int i = 6; i < 8; i++) {
+    auto name = "PROPERTY-" + std::to_string(i + 2);
+    const auto &property = entity.GetProperties().at(i);
+    EXPECT_EQ(property.GetName(), name);
+  }
 
   // AppendProperty another property
   // P0,P1,P2,   P4,P5,P6,   P8,P9
diff --git a/test/test_value.cpp b/test/test_value.cpp
index 25f8a12909e52fee4e3ed3a6b688b1871a41a32f..4e24d9258b287ed9a84538ca04c553e130c73409 100644
--- a/test/test_value.cpp
+++ b/test/test_value.cpp
@@ -22,6 +22,7 @@
 
 #include "caosdb/value.h"                   // for Value
 #include "caosdb/entity/v1alpha1/main.pb.h" // for AtomicDataType, DataType
+#include "caosdb/protobuf_helper.h"         // for ProtoMessageWrapper
 #include <algorithm>                        // for max
 #include <cmath>                            // for isnan
 #include <gtest/gtest-message.h>            // for Message