diff --git a/include/caosdb/data_type.h b/include/caosdb/data_type.h
index d11f2efd4a1619929ed3a9a602e403d4d642c240..38e6e4de53af4bd24b346de06566bde7433a3156 100644
--- a/include/caosdb/data_type.h
+++ b/include/caosdb/data_type.h
@@ -40,7 +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;
+using caosdb::utility::ScalarProtoMessageWrapper;
 
 class Entity;
 class Property;
@@ -69,7 +69,7 @@ const std::map<AtomicDataType, std::string> atomicdatatype_names = {
 class DataType;
 class ListDataType;
 
-class ReferenceDataType : public ScalarFieldWrapper<ProtoDataType> {
+class ReferenceDataType : public ScalarProtoMessageWrapper<ProtoDataType> {
 public:
   [[nodiscard]] inline auto GetName() const noexcept -> const std::string & {
     // is list of reference?
@@ -92,11 +92,11 @@ protected:
   inline static auto Create(ProtoDataType *wrapped) -> std::unique_ptr<ReferenceDataType> {
     return std::unique_ptr<ReferenceDataType>(new ReferenceDataType(wrapped));
   }
-  ReferenceDataType() : ScalarFieldWrapper<ProtoDataType>() {}
-  ReferenceDataType(ProtoDataType *wrapped) : ScalarFieldWrapper<ProtoDataType>(wrapped) {}
+  ReferenceDataType() : ScalarProtoMessageWrapper<ProtoDataType>() {}
+  ReferenceDataType(ProtoDataType *wrapped) : ScalarProtoMessageWrapper<ProtoDataType>(wrapped) {}
 };
 
-class ListDataType : public ScalarFieldWrapper<ProtoDataType> {
+class ListDataType : public ScalarProtoMessageWrapper<ProtoDataType> {
 public:
   [[nodiscard]] inline auto IsListOfReference() const noexcept -> bool {
     return this->wrapped->list_data_type().list_data_type_case() ==
@@ -131,17 +131,17 @@ protected:
   inline static auto Create(ProtoDataType *wrapped) -> std::unique_ptr<ListDataType> {
     return std::unique_ptr<ListDataType>(new ListDataType(wrapped));
   }
-  ListDataType() : ScalarFieldWrapper<ProtoDataType>() {}
+  ListDataType() : ScalarProtoMessageWrapper<ProtoDataType>() {}
 
-  ListDataType(ProtoDataType *wrapped) : ScalarFieldWrapper<ProtoDataType>(wrapped) {}
+  ListDataType(ProtoDataType *wrapped) : ScalarProtoMessageWrapper<ProtoDataType>(wrapped) {}
 
   mutable std::unique_ptr<ReferenceDataType> reference_data_type;
 };
 
-class DataType : public ScalarFieldWrapper<ProtoDataType> {
+class DataType : public ScalarProtoMessageWrapper<ProtoDataType> {
 public:
-  DataType(ProtoDataType *wrapped) : ScalarFieldWrapper<ProtoDataType>(wrapped) {}
-  DataType() : ScalarFieldWrapper<ProtoDataType>() {}
+  DataType(ProtoDataType *wrapped) : ScalarProtoMessageWrapper<ProtoDataType>(wrapped) {}
+  DataType() : ScalarProtoMessageWrapper<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 b2cd0a2a6968967e1b3c4c642b5b98223e3e2e9c..02151d16bdf84af396d5eca1d3a20cd25dbc6aee 100644
--- a/include/caosdb/entity.h
+++ b/include/caosdb/entity.h
@@ -45,7 +45,6 @@
 #include <boost/preprocessor/seq/limits/size_256.hpp>  // for BOOST_PP_SEQ_...
 #include <cstdint>                                     // for int64_t
 #include <google/protobuf/message.h>                   // for RepeatedPtrField
-#include <google/protobuf/util/json_util.h>            // for MessageToJson...
 #include <iosfwd>                                      // for streamsize
 #include <iterator>                                    // for iterator, output_iterato...
 #include <map>                                         // for map
@@ -64,6 +63,8 @@ using ProtoProperty = caosdb::entity::v1alpha1::Property;
 using ProtoEntity = caosdb::entity::v1alpha1::Entity;
 using ProtoFileDescriptor = caosdb::entity::v1alpha1::FileDescriptor;
 using ProtoMessage = caosdb::entity::v1alpha1::Message;
+using ProtoValue = caosdb::entity::v1alpha1::Value;
+using ProtoDataType = caosdb::entity::v1alpha1::DataType;
 using caosdb::entity::v1alpha1::EntityRole;
 using ProtoImportance = caosdb::entity::v1alpha1::Importance;
 using caosdb::StatusCode;
@@ -119,6 +120,8 @@ struct FileDescriptor {
  * Abstract base class for Messages, Properties and Parents container classes.
  *
  * This is a list-like class.
+ *
+ * This class wraps a RepeatedPtrField.
  */
 template <typename T, typename P>
 class RepeatedPtrFieldWrapper : public ProtoMessageWrapper<RepeatedPtrField<P>> {
@@ -297,7 +300,7 @@ 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 : public ScalarFieldWrapper<ProtoMessage> {
+class Message : public ScalarProtoMessageWrapper<ProtoMessage> {
 public:
   // inline Message() {};
   /**
@@ -326,7 +329,8 @@ public:
   friend class RepeatedPtrFieldWrapper<Message, ProtoMessage>;
 
 private:
-  explicit inline Message(ProtoMessage *wrapped) : ScalarFieldWrapper<ProtoMessage>(wrapped){};
+  explicit inline Message(ProtoMessage *wrapped)
+    : ScalarProtoMessageWrapper<ProtoMessage>(wrapped){};
 };
 
 /**
@@ -352,10 +356,10 @@ private:
  * words, this class wraps a protobuf message and provides getter and setter
  * methods.
  */
-class Parent : public ScalarFieldWrapper<ProtoParent> {
+class Parent : public ScalarProtoMessageWrapper<ProtoParent> {
 public:
-  explicit inline Parent(ProtoParent *wrapped) : ScalarFieldWrapper<ProtoParent>(wrapped){};
-  Parent() : ScalarFieldWrapper<ProtoParent>(){};
+  explicit inline Parent(ProtoParent *wrapped) : ScalarProtoMessageWrapper<ProtoParent>(wrapped){};
+  Parent() : ScalarProtoMessageWrapper<ProtoParent>(){};
 
   /**
    * Return the id of the parent entity.
@@ -439,7 +443,7 @@ private:
  * This is a property which belongs to another entity. Don't confuse it with
  * an Entity with the "Property" role.
  */
-class Property : public ScalarFieldWrapper<ProtoProperty> {
+class Property : public ScalarProtoMessageWrapper<ProtoProperty> {
 public:
   /**
    * Copy constructor.
@@ -465,10 +469,10 @@ public:
   }
 
   explicit inline Property(ProtoProperty *other)
-    : ScalarFieldWrapper<ProtoProperty>(other), value(this->wrapped->mutable_value()),
+    : ScalarProtoMessageWrapper<ProtoProperty>(other), value(this->wrapped->mutable_value()),
       data_type(this->wrapped->mutable_data_type()){};
   inline Property()
-    : ScalarFieldWrapper<ProtoProperty>(), value(this->wrapped->mutable_value()),
+    : ScalarProtoMessageWrapper<ProtoProperty>(), value(this->wrapped->mutable_value()),
       data_type(this->wrapped->mutable_data_type()){};
 
   /**
@@ -627,23 +631,22 @@ private:
  * response. calls Entity(), then moves the data to the wrapped ProtoEntity.
  *
  */
-class Entity {
+class Entity : public ScalarProtoMessageWrapper<ProtoEntity> {
 public:
-  inline Entity(const Entity &original) : Entity(Copy(*original.wrapped)) {
+  inline Entity(const Entity &original)
+    : Entity(ProtoMessageWrapper::CopyProtoMessage(original.wrapped)) {
     this->errors.wrapped->CopyFrom(*original.errors.wrapped);
     this->warnings.wrapped->CopyFrom(*original.warnings.wrapped);
     this->infos.wrapped->CopyFrom(*original.infos.wrapped);
   };
   explicit Entity(ProtoEntity *other)
-    : wrapped(other), value(Value(other->mutable_value())),
-      data_type(DataType(other->mutable_data_type())) {
-    data_type.wrapped = this->wrapped->mutable_data_type();
-    value.wrapped = this->wrapped->mutable_value();
+    : ScalarProtoMessageWrapper<ProtoEntity>(other),
+      value(this->wrapped->has_value() ? this->wrapped->mutable_value()
+                                       : static_cast<ProtoValue *>(nullptr)),
+      data_type(this->wrapped->has_data_type() ? this->wrapped->mutable_data_type()
+                                               : static_cast<ProtoDataType *>(nullptr)) {
     properties.wrapped = this->wrapped->mutable_properties();
     parents.wrapped = this->wrapped->mutable_parents();
-    errors.wrapped = CreateMessagesField();
-    warnings.wrapped = CreateMessagesField();
-    infos.wrapped = CreateMessagesField();
   };
   explicit inline Entity(EntityResponse *response) : Entity(response->release_entity()) {
     this->errors.wrapped->Swap(response->mutable_errors());
@@ -659,22 +662,35 @@ public:
     this->infos.wrapped->Swap(id_response->mutable_infos());
   };
 
-  explicit inline Entity() : Entity(Entity::CreateProtoEntity()){};
+  explicit inline Entity()
+    : ScalarProtoMessageWrapper<ProtoEntity>(), value(static_cast<ProtoValue *>(nullptr)),
+      data_type(static_cast<ProtoDataType *>(nullptr)) {
+    properties.wrapped = this->wrapped->mutable_properties();
+    parents.wrapped = this->wrapped->mutable_parents();
+  };
 
-  [[nodiscard]] inline auto GetId() const noexcept -> const std::string & { return wrapped->id(); };
-  [[nodiscard]] inline auto HasId() const noexcept -> bool { return !wrapped->id().empty(); }
+  [[nodiscard]] inline auto GetId() const noexcept -> const std::string & {
+    return this->wrapped->id();
+  };
+  [[nodiscard]] inline auto HasId() const noexcept -> bool { return !this->wrapped->id().empty(); }
   [[nodiscard]] inline auto GetVersionId() const -> const std::string & {
-    return wrapped->version().id();
+    return this->wrapped->version().id();
   };
 
-  [[nodiscard]] inline auto GetRole() const -> Role { return static_cast<Role>(wrapped->role()); };
-  [[nodiscard]] inline auto GetName() const -> const std::string & { return wrapped->name(); };
+  [[nodiscard]] inline auto GetRole() const -> Role {
+    return static_cast<Role>(this->wrapped->role());
+  };
+  [[nodiscard]] inline auto GetName() const -> const std::string & {
+    return this->wrapped->name();
+  };
   [[nodiscard]] inline auto GetDescription() const -> const std::string & {
-    return wrapped->description();
+    return this->wrapped->description();
   };
 
   [[nodiscard]] inline auto GetDataType() const -> const DataType & { return this->data_type; };
-  [[nodiscard]] inline auto GetUnit() const -> const std::string & { return wrapped->unit(); };
+  [[nodiscard]] inline auto GetUnit() const -> const std::string & {
+    return this->wrapped->unit();
+  };
   [[nodiscard]] inline auto GetValue() const -> const Value & { return this->value; };
 
   [[nodiscard]] auto GetParents() const -> const Parents &;
@@ -690,14 +706,6 @@ public:
   [[nodiscard]] auto GetInfos() const -> const Messages & { return infos; }
   [[nodiscard]] inline auto HasInfos() const -> bool { return this->infos.wrapped->size() > 0; }
 
-  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 SetRole(Role role) -> void;
   auto SetName(const std::string &name) -> void;
   /**
@@ -778,11 +786,6 @@ public:
   }
 
 private:
-  static inline auto Copy(const ProtoEntity &from) -> ProtoEntity * {
-    auto to = from.New();
-    to->CopyFrom(from);
-    return to;
-  }
   inline auto GetNextFileId() -> std::string {
     std::string str = "0123456789abcdef";
     std::mt19937 generator(std::random_device{}());
@@ -794,14 +797,12 @@ private:
     }
     return result;
   }
-  static auto CreateProtoEntity() -> ProtoEntity *;
   static auto CreateMessagesField() -> RepeatedPtrField<ProtoMessage> *;
   auto SetId(const std::string &id) -> void;
   auto SetVersionId(const std::string &id) -> void;
 
 private:
   FileDescriptor file_descriptor;
-  ProtoEntity *wrapped;
   Properties properties;
   Parents parents;
   Messages errors;
diff --git a/include/caosdb/protobuf_helper.h b/include/caosdb/protobuf_helper.h
index 18e54003aa04bc09b334557fd69bb30e5ecfeccb..546bcbd8f5ee6700a442a54b85b9f7bc7f380eb1 100644
--- a/include/caosdb/protobuf_helper.h
+++ b/include/caosdb/protobuf_helper.h
@@ -22,7 +22,6 @@
 #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/generated_message_util.h> // for Arena
 #include <google/protobuf/util/json_util.h>         // for JsonOptions, MessageToJs...
@@ -42,6 +41,9 @@ using google::protobuf::Arena;
 
 auto get_arena() -> Arena *;
 
+/**
+ * Abstract wrapper class for Protobuf messages.
+ */
 template <typename P> class ProtoMessageWrapper {
 public:
   virtual ~ProtoMessageWrapper() = 0;
@@ -49,10 +51,6 @@ public:
    * Return a json representation of this object.
    */
   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
@@ -83,11 +81,17 @@ protected:
 
 template <typename P> ProtoMessageWrapper<P>::~ProtoMessageWrapper() = default;
 
-template <typename P> class ScalarFieldWrapper : public ProtoMessageWrapper<P> {
+/**
+ * Wrapper class for scalar Protobuf messages.
+ *
+ * Scalar means in this context, any message but classes derived from
+ * RepeatedPtrField.
+ */
+template <typename P> class ScalarProtoMessageWrapper : public ProtoMessageWrapper<P> {
 public:
-  inline virtual ~ScalarFieldWrapper() = default;
-  inline ScalarFieldWrapper() = default;
-  inline ScalarFieldWrapper(P *wrapped) : ProtoMessageWrapper<P>(wrapped) {}
+  inline virtual ~ScalarProtoMessageWrapper() = default;
+  inline ScalarProtoMessageWrapper() = default;
+  inline ScalarProtoMessageWrapper(P *wrapped) : ProtoMessageWrapper<P>(wrapped) {}
   /**
    * Return a json representation of this object.
    */
diff --git a/include/caosdb/value.h b/include/caosdb/value.h
index 2937f1802fa5bbcacc6227201843c5d251887220..106f378173becf6f40f940be7ada3f9b40899d78 100644
--- a/include/caosdb/value.h
+++ b/include/caosdb/value.h
@@ -31,7 +31,8 @@
 #include <vector>                           // for vector
 
 #define LIST_VALUE_CONSTRUCTOR(TYPE, SETTER)                                                       \
-  explicit inline Value(const std::vector<TYPE> &values) : ScalarFieldWrapper<ProtoValue>() {      \
+  explicit inline Value(const std::vector<TYPE> &values)                                           \
+    : ScalarProtoMessageWrapper<ProtoValue>() {                                                    \
     for (const auto &value : values) {                                                             \
       this->wrapped->mutable_list_values()->add_values()->SETTER(value);                           \
     }                                                                                              \
@@ -40,7 +41,7 @@
 namespace caosdb::entity {
 using caosdb::utility::get_arena;
 using caosdb::utility::ProtoMessageWrapper;
-using caosdb::utility::ScalarFieldWrapper;
+using caosdb::utility::ScalarProtoMessageWrapper;
 using google::protobuf::Arena;
 using ProtoSpecialValue = caosdb::entity::v1alpha1::SpecialValue;
 using ProtoValue = caosdb::entity::v1alpha1::Value;
@@ -168,7 +169,7 @@ protected:
 
 inline AbstractValue::~AbstractValue() {}
 
-class ScalarValue : public AbstractValue, public ScalarFieldWrapper<ProtoScalarValue> {
+class ScalarValue : public AbstractValue, public ScalarProtoMessageWrapper<ProtoScalarValue> {
 public:
   /**
    * Destructor.
@@ -204,7 +205,7 @@ public:
   }
 
   inline ScalarValue(ProtoScalarValue *wrapped)
-    : ScalarFieldWrapper<ProtoScalarValue>(wrapped), proto_value(nullptr) {}
+    : ScalarProtoMessageWrapper<ProtoScalarValue>(wrapped), proto_value(nullptr) {}
 
   [[nodiscard]] inline auto IsNull() const noexcept -> bool {
     return (this->wrapped->scalar_value_case() == ScalarValueCase::kSpecialValue &&
@@ -249,7 +250,7 @@ public:
     return empty_collection;
   }
   [[nodiscard]] inline auto ToString() const noexcept -> const std::string {
-    return ScalarFieldWrapper::ToString();
+    return ScalarProtoMessageWrapper::ToString();
   }
 
   friend class Value;
@@ -262,13 +263,13 @@ protected:
     }
     return this->proto_value;
   };
-  inline ScalarValue() : ScalarFieldWrapper<ProtoScalarValue>(), proto_value(nullptr) {}
+  inline ScalarValue() : ScalarProtoMessageWrapper<ProtoScalarValue>(), proto_value(nullptr) {}
 
 private:
   mutable ProtoValue *proto_value;
 };
 
-class Value : public AbstractValue, public ScalarFieldWrapper<ProtoValue> {
+class Value : public AbstractValue, public ScalarProtoMessageWrapper<ProtoValue> {
 public:
   /**
    * Copy constructor.
@@ -282,7 +283,7 @@ public:
    * Destructor.
    */
   inline ~Value() {}
-  inline Value() : ScalarFieldWrapper<ProtoValue>() {
+  inline Value() : ScalarProtoMessageWrapper<ProtoValue>() {
     // has NULL_VALUE now
   }
   explicit inline Value(const ScalarValue &value) : Value() {
@@ -291,21 +292,21 @@ public:
   explicit inline Value(const AbstractValue &value) : Value() {
     this->wrapped->CopyFrom(*value.GetProtoValue());
   }
-  explicit inline Value(ProtoValue *wrapped) : ScalarFieldWrapper<ProtoValue>(wrapped) {}
-  explicit inline Value(const std::string &value) : ScalarFieldWrapper<ProtoValue>() {
+  explicit inline Value(ProtoValue *wrapped) : ScalarProtoMessageWrapper<ProtoValue>(wrapped) {}
+  explicit inline Value(const std::string &value) : ScalarProtoMessageWrapper<ProtoValue>() {
     this->wrapped->mutable_scalar_value()->set_string_value(value);
   }
-  explicit inline Value(const char *value) : ScalarFieldWrapper<ProtoValue>() {
+  explicit inline Value(const char *value) : ScalarProtoMessageWrapper<ProtoValue>() {
     this->wrapped->mutable_scalar_value()->set_string_value(std::string(value));
   }
-  explicit inline Value(double value) : ScalarFieldWrapper<ProtoValue>() {
+  explicit inline Value(double value) : ScalarProtoMessageWrapper<ProtoValue>() {
     this->wrapped->mutable_scalar_value()->set_double_value(value);
   }
-  explicit inline Value(int64_t value) : ScalarFieldWrapper<ProtoValue>() {
+  explicit inline Value(int64_t value) : ScalarProtoMessageWrapper<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) : ScalarFieldWrapper<ProtoValue>() {
+  explicit inline Value(bool value) : ScalarProtoMessageWrapper<ProtoValue>() {
     this->wrapped->mutable_scalar_value()->set_boolean_value(value);
   }
 
@@ -411,7 +412,7 @@ public:
   }
 
   [[nodiscard]] inline auto ToString() const noexcept -> const std::string {
-    return ScalarFieldWrapper::ToString();
+    return ScalarProtoMessageWrapper::ToString();
   }
 
   friend class Entity;
diff --git a/src/caosdb/entity.cpp b/src/caosdb/entity.cpp
index 050a9bd0fe3b9a2c0dcf213d17a47aa204ce8240..8a2e788a7e039cca9d9c6b036efad3656c3f72b0 100644
--- a/src/caosdb/entity.cpp
+++ b/src/caosdb/entity.cpp
@@ -163,10 +163,6 @@ auto Entity::AppendProperty(const Property &property) -> void { this->properties
 
 auto Entity::RemoveProperty(int index) -> void { this->properties.Remove(index); }
 
-auto Entity::CreateProtoEntity() -> ProtoEntity * {
-  return Arena::CreateMessage<ProtoEntity>(get_arena());
-}
-
 auto Entity::CreateMessagesField() -> RepeatedPtrField<ProtoMessage> * {
   return Arena::CreateMessage<RepeatedPtrField<ProtoMessage>>(get_arena());
 }
diff --git a/test/test_data_type.cpp b/test/test_data_type.cpp
index 51624a7e0513f4654f2eaa9fdf3519399726199d..78e5100f3ce984ece46918df4aca9ffb8f1d2522 100644
--- a/test/test_data_type.cpp
+++ b/test/test_data_type.cpp
@@ -117,4 +117,16 @@ TEST(test_data_type, test_list_of_reference) {
   EXPECT_EQ(list_data_type.GetReferenceDataType().GetName(), "person");
 }
 
+TEST(test_data_type, test_data_type_to_string) {
+  DataType data_type1;
+  EXPECT_EQ(data_type1.ToString(), "{}\n");
+
+  ProtoDataType proto_data_type;
+  DataType data_type2(&proto_data_type);
+  EXPECT_EQ(data_type2.ToString(), "{}\n");
+
+  DataType data_type3(AtomicDataType::INTEGER);
+  EXPECT_EQ(data_type3.ToString(), "{\n \"atomicDataType\": \"ATOMIC_DATA_TYPE_INTEGER\"\n}\n");
+}
+
 } // namespace caosdb::entity
diff --git a/test/test_entity.cpp b/test/test_entity.cpp
index ad74ef6677947fcdf8c310a272584a0e54e69e88..0987f6b07d25edfa6607800f6864640bda535596 100644
--- a/test/test_entity.cpp
+++ b/test/test_entity.cpp
@@ -565,4 +565,9 @@ TEST(test_entity, test_add_file) {
   EXPECT_EQ(entity.SetLocalPath(TEST_DATA_DIR + "/test.json"), StatusCode::SUCCESS);
 }
 
+TEST(test_entity, test_entity_to_string) {
+  Entity entity;
+  EXPECT_EQ(entity.ToString(), "{}\n");
+}
+
 } // namespace caosdb::entity
diff --git a/test/test_value.cpp b/test/test_value.cpp
index 4e24d9258b287ed9a84538ca04c553e130c73409..241f2bd0ce2a7291184a79cdaa0612f2b99fa204 100644
--- a/test/test_value.cpp
+++ b/test/test_value.cpp
@@ -33,6 +33,7 @@
 #include <vector>                           // for vector
 
 namespace caosdb::entity {
+using ProtoValue = caosdb::entity::v1alpha1::Value;
 using ProtoEntity = caosdb::entity::v1alpha1::Entity;
 using ProtoParent = caosdb::entity::v1alpha1::Parent;
 using ProtoDataType = caosdb::entity::v1alpha1::DataType;
@@ -175,4 +176,21 @@ TEST(test_value, test_abstract_value) {
   EXPECT_EQ(scalar_value2.GetAsDouble(), 27.5);
 }
 
+TEST(test_value, test_value_to_string) {
+  Value value1;
+  EXPECT_EQ(value1.ToString(), "{}\n");
+
+  ProtoValue proto_value;
+  Value value2(&proto_value);
+  EXPECT_EQ(value2.ToString(), "{}\n");
+
+  Value value3(2.6);
+  EXPECT_EQ(value3.ToString(), "{\n \"scalarValue\": {\n  \"doubleValue\": 2.6\n }\n}\n");
+
+  Value value4(std::vector<bool>{true, false});
+  EXPECT_EQ(value4.ToString(),
+            "{\n \"listValues\": {\n  \"values\": [\n   {\n    \"booleanValue\": true\n   },\n   "
+            "{\n    \"booleanValue\": false\n   }\n  ]\n }\n}\n");
+}
+
 } // namespace caosdb::entity