diff --git a/include/caosdb/data_type.h b/include/caosdb/data_type.h
index 38e6e4de53af4bd24b346de06566bde7433a3156..42d376698872e086c05a5905484e2f63c11dd346 100644
--- a/include/caosdb/data_type.h
+++ b/include/caosdb/data_type.h
@@ -141,11 +141,12 @@ protected:
 class DataType : public ScalarProtoMessageWrapper<ProtoDataType> {
 public:
   DataType(ProtoDataType *wrapped) : ScalarProtoMessageWrapper<ProtoDataType>(wrapped) {}
-  DataType() : ScalarProtoMessageWrapper<ProtoDataType>() {}
+  DataType() : ScalarProtoMessageWrapper<ProtoDataType>(static_cast<ProtoDataType *>(nullptr)) {}
   /**
    * Create an AtomicDataType typed DataType.  For references, use the std::string constructor.
    */
-  DataType(AtomicDataType data_type, bool list_type = false) : DataType() {
+  DataType(AtomicDataType data_type, bool list_type = false)
+    : ScalarProtoMessageWrapper<ProtoDataType>() {
     if (list_type) {
       this->wrapped->mutable_list_data_type()->set_atomic_data_type(
         static_cast<ProtoAtomicDataType>(data_type));
@@ -156,7 +157,8 @@ public:
   /**
    * Create a reference typed DataType.
    */
-  DataType(const std::string &data_type, bool list_type = false) : DataType() {
+  DataType(const std::string &data_type, bool list_type = false)
+    : ScalarProtoMessageWrapper<ProtoDataType>() {
     if (list_type) {
       this->wrapped->mutable_list_data_type()->mutable_reference_data_type()->set_name(data_type);
     } else {
@@ -165,27 +167,28 @@ public:
   }
 
   inline static auto ListOf(const AtomicDataType &atomic_data_type) -> DataType {
-    DataType result;
-    result.wrapped->mutable_list_data_type()->set_atomic_data_type(
-      static_cast<ProtoAtomicDataType>(atomic_data_type));
-    return result;
+    return DataType(atomic_data_type, true);
   }
   inline static auto ListOf(const std::string reference_data_type) -> DataType {
-    DataType result;
-    result.wrapped->mutable_list_data_type()->mutable_reference_data_type()->set_name(
-      reference_data_type);
-    return result;
+    return DataType(reference_data_type, true);
   }
 
+  [[nodiscard]] inline auto IsUndefined() const noexcept -> bool {
+    return this->wrapped == nullptr;
+  }
   [[nodiscard]] inline auto IsAtomic() const noexcept -> bool {
-    return this->wrapped->data_type_case() == DataTypeCase::kAtomicDataType;
+    return !IsUndefined() && this->wrapped->data_type_case() == DataTypeCase::kAtomicDataType;
   }
   [[nodiscard]] inline auto GetAsAtomic() const noexcept -> AtomicDataType {
+    if (!IsAtomic()) {
+      static AtomicDataType undefined;
+      return undefined;
+    }
     return static_cast<AtomicDataType>(this->wrapped->atomic_data_type());
   }
 
   [[nodiscard]] inline auto IsReference() const noexcept -> bool {
-    return this->wrapped->data_type_case() == DataTypeCase::kReferenceDataType;
+    return !IsUndefined() && this->wrapped->data_type_case() == DataTypeCase::kReferenceDataType;
   }
   [[nodiscard]] inline auto GetAsReference() const noexcept -> const ReferenceDataType & {
     if (!IsReference()) {
@@ -198,7 +201,7 @@ public:
   }
 
   [[nodiscard]] inline auto IsList() const noexcept -> bool {
-    return this->wrapped->data_type_case() == DataTypeCase::kListDataType;
+    return !IsUndefined() && this->wrapped->data_type_case() == DataTypeCase::kListDataType;
   }
 
   [[nodiscard]] inline auto GetAsList() const noexcept -> const ListDataType & {
@@ -210,9 +213,18 @@ public:
     return *list_data_type;
   }
 
+  /**
+   * Return true if `other` is equal to this object.
+   *
+   * This compares the underlying wrapped ProtoMessages and return true if they
+   * are both nullptrs or if the serialization is equal.
+   */
   inline auto operator==(const DataType &other) const noexcept -> bool {
-    // TODO(tf) Is this safe?
-    return this->wrapped->SerializeAsString() == other.wrapped->SerializeAsString();
+    if (this->wrapped != nullptr && other.wrapped != nullptr) {
+      return this->wrapped->SerializeAsString() == other.wrapped->SerializeAsString();
+    }
+    // both nullptr?
+    return this->wrapped == other.wrapped;
   }
 
   friend class Entity;
diff --git a/include/caosdb/protobuf_helper.h b/include/caosdb/protobuf_helper.h
index c82a88fa7c79415d3cac7c383abf67bc5ff4d2a8..667a4747c00a544bc6a526034b8d592451b7aa8e 100644
--- a/include/caosdb/protobuf_helper.h
+++ b/include/caosdb/protobuf_helper.h
@@ -99,6 +99,9 @@ public:
    * Return a json representation of this object.
    */
   inline auto ToString() const noexcept -> const std::string override {
+    if (this->wrapped == nullptr) {
+      return "{}\n";
+    }
     CAOSDB_DEBUG_MESSAGE_STRING(*this->wrapped, out)
     return out;
   }
diff --git a/include/caosdb/value.h b/include/caosdb/value.h
index 106f378173becf6f40f940be7ada3f9b40899d78..8296be311a8262339b58de06d49940100fc183f3 100644
--- a/include/caosdb/value.h
+++ b/include/caosdb/value.h
@@ -208,34 +208,36 @@ public:
     : ScalarProtoMessageWrapper<ProtoScalarValue>(wrapped), proto_value(nullptr) {}
 
   [[nodiscard]] inline auto IsNull() const noexcept -> bool {
-    return (this->wrapped->scalar_value_case() == ScalarValueCase::kSpecialValue &&
+    return this->wrapped == nullptr ||
+           (this->wrapped->scalar_value_case() == ScalarValueCase::kSpecialValue &&
             this->wrapped->special_value() == ProtoSpecialValue::SPECIAL_VALUE_UNSPECIFIED);
   }
   [[nodiscard]] inline auto IsString() const noexcept -> bool {
-    return (this->wrapped->scalar_value_case() == ScalarValueCase::kStringValue) ||
-           (this->wrapped->scalar_value_case() == ScalarValueCase::kSpecialValue &&
-            this->wrapped->special_value() == ProtoSpecialValue::SPECIAL_VALUE_EMPTY_STRING);
+    return !IsNull() &&
+           ((this->wrapped->scalar_value_case() == ScalarValueCase::kStringValue) ||
+            (this->wrapped->scalar_value_case() == ScalarValueCase::kSpecialValue &&
+             this->wrapped->special_value() == ProtoSpecialValue::SPECIAL_VALUE_EMPTY_STRING));
   }
   [[nodiscard]] inline auto GetAsString() const noexcept -> const std::string & {
     return this->wrapped->string_value();
   }
 
   [[nodiscard]] inline auto IsDouble() const noexcept -> bool {
-    return (this->wrapped->scalar_value_case() == ScalarValueCase::kDoubleValue);
+    return !IsNull() && (this->wrapped->scalar_value_case() == ScalarValueCase::kDoubleValue);
   }
   [[nodiscard]] inline auto GetAsDouble() const noexcept -> double {
     return this->wrapped->double_value();
   }
 
   [[nodiscard]] inline auto IsInt64() const noexcept -> bool {
-    return (this->wrapped->scalar_value_case() == ScalarValueCase::kIntegerValue);
+    return !IsNull() && (this->wrapped->scalar_value_case() == ScalarValueCase::kIntegerValue);
   }
   [[nodiscard]] inline auto GetAsInt64() const noexcept -> int64_t {
     return this->wrapped->integer_value();
   }
 
   [[nodiscard]] inline auto IsBool() const noexcept -> bool {
-    return (this->wrapped->scalar_value_case() == ScalarValueCase::kBooleanValue);
+    return !IsNull() && (this->wrapped->scalar_value_case() == ScalarValueCase::kBooleanValue);
   }
   [[nodiscard]] inline auto GetAsBool() const noexcept -> bool {
     return this->wrapped->boolean_value();
@@ -274,7 +276,9 @@ public:
   /**
    * Copy constructor.
    */
-  inline Value(const Value &original) : Value() { this->wrapped->CopyFrom(*original.wrapped); }
+  inline Value(const Value &original) : ScalarProtoMessageWrapper<ProtoValue>() {
+    this->wrapped->CopyFrom(*original.wrapped);
+  }
   /**
    * Move constructor.
    */
@@ -283,13 +287,13 @@ public:
    * Destructor.
    */
   inline ~Value() {}
-  inline Value() : ScalarProtoMessageWrapper<ProtoValue>() {
+  inline Value() : ScalarProtoMessageWrapper<ProtoValue>(static_cast<ProtoValue *>(nullptr)) {
     // has NULL_VALUE now
   }
-  explicit inline Value(const ScalarValue &value) : Value() {
+  explicit inline Value(const ScalarValue &value) : ScalarProtoMessageWrapper<ProtoValue>() {
     this->wrapped->mutable_scalar_value()->CopyFrom(*value.wrapped);
   }
-  explicit inline Value(const AbstractValue &value) : Value() {
+  explicit inline Value(const AbstractValue &value) : ScalarProtoMessageWrapper<ProtoValue>() {
     this->wrapped->CopyFrom(*value.GetProtoValue());
   }
   explicit inline Value(ProtoValue *wrapped) : ScalarProtoMessageWrapper<ProtoValue>(wrapped) {}
@@ -318,14 +322,15 @@ public:
   LIST_VALUE_CONSTRUCTOR(bool, set_boolean_value)
 
   [[nodiscard]] inline auto IsNull() const noexcept -> bool {
-    return this->wrapped->value_case() == ValueCase::VALUE_NOT_SET ||
-           (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kSpecialValue &&
-            this->wrapped->scalar_value().special_value() ==
-              ProtoSpecialValue::SPECIAL_VALUE_UNSPECIFIED);
+    return this->wrapped == nullptr ||
+           (this->wrapped->value_case() == ValueCase::VALUE_NOT_SET ||
+            (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kSpecialValue &&
+             this->wrapped->scalar_value().special_value() ==
+               ProtoSpecialValue::SPECIAL_VALUE_UNSPECIFIED));
   }
 
   [[nodiscard]] inline auto IsString() const noexcept -> bool {
-    if (this->wrapped->value_case() == ValueCase::kScalarValue) {
+    if (!IsNull() && this->wrapped->value_case() == ValueCase::kScalarValue) {
 
       return (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kStringValue) ||
              (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kSpecialValue &&
@@ -335,50 +340,60 @@ public:
     return false;
   }
   [[nodiscard]] inline auto GetAsString() const noexcept -> const std::string & {
+    if (!IsString()) {
+      static std::string empty_string;
+      return empty_string;
+    }
     return this->wrapped->scalar_value().string_value();
-    ;
   }
 
   [[nodiscard]] inline auto IsDouble() const noexcept -> bool {
-    if (this->wrapped->value_case() == ValueCase::kScalarValue) {
+    if (!IsNull() && this->wrapped->value_case() == ValueCase::kScalarValue) {
 
       return (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kDoubleValue);
     }
     return false;
   }
   [[nodiscard]] inline auto GetAsDouble() const noexcept -> double {
+    if (!IsDouble())
+      return 0.0;
     return this->wrapped->scalar_value().double_value();
   }
 
   [[nodiscard]] inline auto IsInt64() const noexcept -> bool {
-    if (this->wrapped->value_case() == ValueCase::kScalarValue) {
+    if (!IsNull() && this->wrapped->value_case() == ValueCase::kScalarValue) {
 
       return (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kIntegerValue);
     }
     return false;
   }
   [[nodiscard]] inline auto GetAsInt64() const noexcept -> int64_t {
+    if (!IsInt64())
+      return 0;
     return this->wrapped->scalar_value().integer_value();
   }
 
   [[nodiscard]] inline auto IsBool() const noexcept -> bool {
-    if (this->wrapped->value_case() == ValueCase::kScalarValue) {
+    if (!IsNull() && this->wrapped->value_case() == ValueCase::kScalarValue) {
 
       return (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kBooleanValue);
     }
     return false;
   }
   [[nodiscard]] inline auto GetAsBool() const noexcept -> bool {
+    if (!IsBool())
+      return false;
     return this->wrapped->scalar_value().boolean_value();
   }
 
   [[nodiscard]] inline auto IsVector() const noexcept -> bool {
-    return this->wrapped->value_case() == ValueCase::kListValues;
+    return !IsNull() && this->wrapped->value_case() == ValueCase::kListValues;
   }
   [[nodiscard]] inline auto GetAsVector() const noexcept -> const std::vector<ScalarValue> & {
     if (!IsVector()) {
       // create empty list
-      this->collection_values = std::make_unique<std::vector<ScalarValue>>();
+      static std::vector<ScalarValue> empty_values;
+      return empty_values;
     }
     if (this->collection_values == nullptr) {
       this->collection_values = std::make_unique<std::vector<ScalarValue>>();
diff --git a/src/caosdb/entity.cpp b/src/caosdb/entity.cpp
index 8a2e788a7e039cca9d9c6b036efad3656c3f72b0..bb73431e4af00ed1db48b8f87fa883db6f4f9b31 100644
--- a/src/caosdb/entity.cpp
+++ b/src/caosdb/entity.cpp
@@ -91,8 +91,13 @@ auto Property::SetImportance(Importance importance) -> void {
 }
 
 auto Property::SetValue(const Value &value) -> StatusCode {
-  this->wrapped->mutable_value()->CopyFrom(*value.wrapped);
-  this->value = Value(this->wrapped->mutable_value());
+  if (value.wrapped == nullptr) {
+    this->wrapped->clear_value();
+    this->value = Value();
+  } else {
+    this->wrapped->mutable_value()->CopyFrom(*value.wrapped);
+    this->value = Value(this->wrapped->mutable_value());
+  }
   return StatusCode::SUCCESS;
 }
 
@@ -137,8 +142,13 @@ auto Property::SetValue(const bool value) -> StatusCode { return SetValue(Value(
 auto Property::SetUnit(const std::string &unit) -> void { this->wrapped->set_unit(unit); }
 
 auto Property::SetDataType(const DataType &new_data_type) -> StatusCode {
-  this->wrapped->mutable_data_type()->CopyFrom(*new_data_type.wrapped);
-  this->data_type = DataType(this->wrapped->mutable_data_type());
+  if (new_data_type.wrapped == nullptr) {
+    this->wrapped->clear_data_type();
+    this->data_type = DataType();
+  } else {
+    this->wrapped->mutable_data_type()->CopyFrom(*new_data_type.wrapped);
+    this->data_type = DataType(this->wrapped->mutable_data_type());
+  }
   return StatusCode::SUCCESS;
 }
 
@@ -187,8 +197,13 @@ auto Entity::SetValue(const Value &value) -> StatusCode {
   if (GetRole() != Role::PROPERTY) {
     return StatusCode::ENTITY_CANNOT_HAVE_A_VALUE;
   }
-  this->wrapped->mutable_value()->CopyFrom(*value.wrapped);
-  this->value = Value(this->wrapped->mutable_value());
+  if (value.wrapped == nullptr) {
+    this->wrapped->clear_value();
+    this->value = Value();
+  } else {
+    this->wrapped->mutable_value()->CopyFrom(*value.wrapped);
+    this->value = Value(this->wrapped->mutable_value());
+  }
   return StatusCode::SUCCESS;
 }
 
@@ -236,8 +251,13 @@ auto Entity::SetDataType(const DataType &new_data_type) -> StatusCode {
   if (GetRole() != Role::PROPERTY) {
     return StatusCode::ENTITY_CANNOT_HAVE_A_DATA_TYPE;
   }
-  this->wrapped->mutable_data_type()->CopyFrom(*new_data_type.wrapped);
-  this->data_type = DataType(this->wrapped->mutable_data_type());
+  if (new_data_type.wrapped == nullptr) {
+    this->wrapped->clear_data_type();
+    this->data_type = DataType();
+  } else {
+    this->wrapped->mutable_data_type()->CopyFrom(*new_data_type.wrapped);
+    this->data_type = DataType(this->wrapped->mutable_data_type());
+  }
   return StatusCode::SUCCESS;
 }
 
diff --git a/test/test_entity.cpp b/test/test_entity.cpp
index 8f0a5fd9997a1bd143e636347bc060ada09cf200..de0206f8b547884b7ae438b3bd4873230b9128d8 100644
--- a/test/test_entity.cpp
+++ b/test/test_entity.cpp
@@ -568,6 +568,15 @@ TEST(test_entity, test_add_file) {
 TEST(test_entity, test_entity_to_string) {
   Entity entity;
   EXPECT_EQ(entity.ToString(), "{}\n");
+
+  entity.SetRole(Role::PROPERTY);
+  EXPECT_EQ(entity.ToString(), "{\n \"role\": \"ENTITY_ROLE_PROPERTY\"\n}\n");
+
+  entity.SetValue(Value());
+  EXPECT_EQ(entity.ToString(), "{\n \"role\": \"ENTITY_ROLE_PROPERTY\"\n}\n");
+
+  entity.SetDataType(DataType());
+  EXPECT_EQ(entity.ToString(), "{\n \"role\": \"ENTITY_ROLE_PROPERTY\"\n}\n");
 }
 
 TEST(test_entity, test_properties_to_string) {