diff --git a/CMakeLists.txt b/CMakeLists.txt
index e931347885bc39a64e131d8ae8003a67ebf72847..97830558c446a3e6718d68b8ba2cee7c033bd88d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,7 +20,7 @@
 
 cmake_minimum_required(VERSION 3.13)
 
-set(libcaosdb_VERSION 0.0.16)
+set(libcaosdb_VERSION 0.0.17)
 set(libcaosdb_COMPATIBLE_SERVER_VERSION_MAJOR 0)
 set(libcaosdb_COMPATIBLE_SERVER_VERSION_MINOR 5)
 set(libcaosdb_COMPATIBLE_SERVER_VERSION_PATCH 0)
diff --git a/conanfile.py b/conanfile.py
index 3748da681bff0aa278059c0a4e42df0d6432e67a..7a712bbd99136c5054f7a8fedeee6fb5af5ce4f7 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -3,7 +3,7 @@ from conans import ConanFile, CMake, tools
 
 class CaosdbConan(ConanFile):
     name = "caosdb"
-    version = "0.0.16"
+    version = "0.0.17"
     license = "AGPL-3.0-or-later"
     author = "Timm C. Fitschen <t.fitschen@indiscale.com>"
     url = "https://gitlab.indiscale.com/caosdb/src/caosdb-cpplib.git"
diff --git a/include/caosdb/data_type.h b/include/caosdb/data_type.h
index 22358fcda808c8ebf93c140156ba7e39c5757e8d..e6b92d53d6ddb1aa8360af55f6438d23eafff7ae 100644
--- a/include/caosdb/data_type.h
+++ b/include/caosdb/data_type.h
@@ -179,14 +179,14 @@ public:
   [[nodiscard]] inline auto IsAtomic() const noexcept -> bool {
     return this->wrapped->data_type_case() == DataTypeCase::kAtomicDataType;
   }
-  [[nodiscard]] inline auto AsAtomic() const noexcept -> AtomicDataType {
+  [[nodiscard]] inline auto GetAsAtomic() const noexcept -> AtomicDataType {
     return static_cast<AtomicDataType>(this->wrapped->atomic_data_type());
   }
 
   [[nodiscard]] inline auto IsReference() const noexcept -> bool {
     return this->wrapped->data_type_case() == DataTypeCase::kReferenceDataType;
   }
-  [[nodiscard]] inline auto AsReference() const noexcept -> const ReferenceDataType & {
+  [[nodiscard]] inline auto GetAsReference() const noexcept -> const ReferenceDataType & {
     if (!IsReference()) {
       return ReferenceDataType::GetEmptyInstance();
     } else if (reference_data_type == nullptr) {
@@ -200,7 +200,7 @@ public:
     return this->wrapped->data_type_case() == DataTypeCase::kListDataType;
   }
 
-  [[nodiscard]] inline auto AsList() const noexcept -> const ListDataType & {
+  [[nodiscard]] inline auto GetAsList() const noexcept -> const ListDataType & {
     if (!IsList()) {
       return ListDataType::GetEmptyInstance();
     } else if (list_data_type == nullptr) {
diff --git a/include/caosdb/entity.h b/include/caosdb/entity.h
index fea060d726d67c0cf6f21d42f6b8f3ead0622671..de6d4928771af83edca68d748d73b58f690a35f7 100644
--- a/include/caosdb/entity.h
+++ b/include/caosdb/entity.h
@@ -515,6 +515,7 @@ public:
    * Set the value of this property.
    */
   auto SetValue(const Value &value) -> StatusCode;
+  auto SetValue(const AbstractValue &value) -> StatusCode;
   auto SetValue(const std::string &value) -> StatusCode;
   auto SetValue(const char *value) -> StatusCode;
   auto SetValue(const double value) -> StatusCode;
@@ -687,6 +688,7 @@ public:
    */
   auto SetDescription(const std::string &description) -> void;
 
+  auto SetValue(const AbstractValue &value) -> StatusCode;
   auto SetValue(const Value &value) -> StatusCode;
   auto SetValue(const std::string &value) -> StatusCode;
   auto SetValue(const char *value) -> StatusCode;
diff --git a/include/caosdb/value.h b/include/caosdb/value.h
index 6031e75dbd69c262cc69079c63323d916cec223d..7bf0f7d3f9a7e0c55f7ccf48fd0af536baec5e1e 100644
--- a/include/caosdb/value.h
+++ b/include/caosdb/value.h
@@ -22,12 +22,17 @@
 #ifndef CAOSDB_VALUE_H
 #define CAOSDB_VALUE_H
 #include "caosdb/protobuf_helper.h"         // for ProtoMessageWrapper
+#include "caosdb/logging.h"                 // IWYU pragma: keep
 #include "caosdb/entity/v1alpha1/main.pb.h" // for RepeatedPtrField, Message
-#include "caosdb/logging.h"
-#include <google/protobuf/util/json_util.h> // for MessageToJson...
-#include <memory>                           // for unique_ptr
-#include <string>                           // for string
-#include <vector>                           // for vector
+
+#include <cstdint>                                  // for int64_t
+#include <google/protobuf/arena.h>                  // for Arena
+#include <google/protobuf/generated_message_util.h> // for Arena
+#include <google/protobuf/util/json_util.h>         // IWYU pragma: keep
+#include <memory>                                   // for unique_ptr
+#include <string>                                   // for string, operator==
+#include <utility>                                  // for move
+#include <vector>                                   // for vector
 
 #define LIST_VALUE_CONSTRUCTOR(TYPE, SETTER)                                                       \
   explicit inline Value(const std::vector<TYPE> &values) : ProtoMessageWrapper<ProtoValue>() {     \
@@ -37,15 +42,17 @@
   }
 
 namespace caosdb::entity {
+using caosdb::utility::get_arena;
 using caosdb::utility::ProtoMessageWrapper;
+using google::protobuf::Arena;
 using ProtoSpecialValue = caosdb::entity::v1alpha1::SpecialValue;
 using ProtoValue = caosdb::entity::v1alpha1::Value;
 using ProtoScalarValue = caosdb::entity::v1alpha1::ScalarValue;
 using ValueCase = caosdb::entity::v1alpha1::Value::ValueCase;
 using ScalarValueCase = caosdb::entity::v1alpha1::ScalarValue::ScalarValueCase;
 
-class Entity;
-class Property;
+class ScalarValue;
+class Value;
 
 // Represents special values which are otherwise hard to tranfer via protobuf.
 enum SpecialValue {
@@ -55,46 +62,239 @@ enum SpecialValue {
   EMPTY_STRING = ProtoSpecialValue::SPECIAL_VALUE_EMPTY_STRING,
 };
 
-class ScalarValue : public ProtoMessageWrapper<ProtoScalarValue> {
+/**
+ * Pure abstract base class for values.
+ */
+class AbstractValue {
 public:
-  inline ScalarValue(ProtoScalarValue *wrapped) : ProtoMessageWrapper<ProtoScalarValue>(wrapped) {}
+  /**
+   * Pure virtual destructor.
+   */
+  virtual ~AbstractValue() = 0;
+  /**
+   * Return true iff the value is a NULL value (NULL in the CaosDB sense).
+   */
+  [[nodiscard]] virtual auto IsNull() const noexcept -> bool = 0;
+  /**
+   * Return true iff the value is best represented in C++ types as a
+   * std::string.
+   *
+   * If true, clients may call GetAsString to receive a std::string
+   * representation of the value.
+   */
+  [[nodiscard]] virtual auto IsString() const noexcept -> bool = 0;
+  /**
+   * Return true iff the value is best represented in C++ types as a
+   * bool.
+   *
+   * If true, clients may call GetAsBool to receive a bool
+   * representation of the value.
+   */
+  [[nodiscard]] virtual auto IsBool() const noexcept -> bool = 0;
+  /**
+   * Return true iff the value is best represented in C++ types as a
+   * double.
+   *
+   * If true, clients may call GetAsDouble to receive a double
+   * representation of the value.
+   */
+  [[nodiscard]] virtual auto IsDouble() const noexcept -> bool = 0;
+  /**
+   * Return true iff the value is best represented in C++ types as an
+   * int64_t.
+   *
+   * If true, clients may call GetAsInt64 to receive an int64_t
+   * representation of the value.
+   */
+  [[nodiscard]] virtual auto IsInt64() const noexcept -> bool = 0;
+  /**
+   * Return true iff the value is best represented in C++ types as a
+   * std::vector<ScalarValue>.
+   *
+   * If true, clients may call GetAsVector to receive a
+   * std::vector<ScalarValue> representation of the value.
+   */
+  [[nodiscard]] virtual auto IsVector() const noexcept -> bool = 0;
+
+  /**
+   * Return a std::string representation of this value.
+   *
+   * Clients should call IsString before calling this function in order to
+   * assure that this value is indeed best represented by a std::string.
+   *
+   * The return value is undefined if IsString is false.
+   */
+  [[nodiscard]] virtual auto GetAsString() const noexcept -> const std::string & = 0;
+  /**
+   * Return a bool representation of this value.
+   *
+   * Clients should call IsBool before calling this function in order to
+   * assure that this value is indeed best represented by a bool.
+   *
+   * The return value is undefined if IsBool is false.
+   */
+  [[nodiscard]] virtual auto GetAsBool() const noexcept -> bool = 0;
+  /**
+   * Return a double representation of this value.
+   *
+   * Clients should call IsDouble before calling this function in order to
+   * assure that this value is indeed best represented by a double.
+   *
+   * The return value is undefined if IsDouble is false.
+   */
+  [[nodiscard]] virtual auto GetAsDouble() const noexcept -> double = 0;
+  /**
+   * Return an int64_t representation of this value.
+   *
+   * Clients should call IsInt64 before calling this function in order to
+   * assure that this value is indeed best represented by an int64_t.
+   *
+   * The return value is undefined if IsInt64 is false.
+   */
+  [[nodiscard]] virtual auto GetAsInt64() const noexcept -> int64_t = 0;
+  /**
+   * Return a std::vector<ScalarValue> representation of this value.
+   *
+   * Clients should call IsVector before calling this function in order to
+   * assure that this value is indeed best represented by a
+   * std::vector<ScalarValue>.
+   *
+   * The return value is undefined if IsVector is false.
+   */
+  [[nodiscard]] virtual auto GetAsVector() const noexcept -> const std::vector<ScalarValue> & = 0;
+  [[nodiscard]] virtual auto ToString() const noexcept -> const std::string = 0;
+  friend class Value;
+
+protected:
+  [[nodiscard]] virtual auto GetProtoValue() const noexcept -> const ProtoValue * = 0;
+};
 
+inline AbstractValue::~AbstractValue() {}
+
+class ScalarValue : public AbstractValue, public ProtoMessageWrapper<ProtoScalarValue> {
+public:
+  /**
+   * Destructor.
+   */
+  inline ~ScalarValue(){};
+  /**
+   * Copy constructor.
+   */
+  inline ScalarValue(const ScalarValue &original) : ScalarValue() {
+    this->wrapped->CopyFrom(*original.wrapped);
+  }
+  /**
+   * Move constructor.
+   */
+  inline ScalarValue(ScalarValue &&other) : ScalarValue(std::move(other.wrapped)){};
+  /**
+   * Copy assignment operator.
+   */
+  inline auto operator=(const ScalarValue &original) -> ScalarValue & {
+    if (&original != this) {
+      this->wrapped->CopyFrom(*original.wrapped);
+    }
+    return *this;
+  }
+  /**
+   * Move assignment operator.
+   */
+  inline auto operator=(ScalarValue &&other) -> ScalarValue & {
+    if (&other != this) {
+      this->wrapped = std::move(other.wrapped);
+    }
+    return *this;
+  }
+
+  inline ScalarValue(ProtoScalarValue *wrapped)
+    : ProtoMessageWrapper<ProtoScalarValue>(wrapped), proto_value(nullptr) {}
+
+  [[nodiscard]] inline auto IsNull() const noexcept -> bool {
+    return (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);
   }
-  [[nodiscard]] inline auto AsString() const noexcept -> const std::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);
   }
-  [[nodiscard]] inline auto AsDouble() const noexcept -> double {
+  [[nodiscard]] inline auto GetAsDouble() const noexcept -> double {
     return this->wrapped->double_value();
   }
 
-  [[nodiscard]] inline auto IsInteger() const noexcept -> bool {
+  [[nodiscard]] inline auto IsInt64() const noexcept -> bool {
     return (this->wrapped->scalar_value_case() == ScalarValueCase::kIntegerValue);
   }
-  [[nodiscard]] inline auto AsInteger() const noexcept -> int64_t {
+  [[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);
   }
-  [[nodiscard]] inline auto AsBool() const noexcept -> bool {
+  [[nodiscard]] inline auto GetAsBool() const noexcept -> bool {
     return this->wrapped->boolean_value();
   }
+  [[nodiscard]] auto IsVector() const noexcept -> bool {
+    // Always false b/c a scalar value is never a collection.
+    return false;
+  }
+  [[nodiscard]] auto GetAsVector() const noexcept -> const std::vector<ScalarValue> & {
+    // Always return an empty vector.
+    static const std::vector<ScalarValue> empty_collection;
+    return empty_collection;
+  }
+  inline auto ToString() const noexcept -> const std::string {
+    CAOSDB_DEBUG_MESSAGE_STRING(*wrapped, out)
+    return out;
+  }
+
+  friend class Value;
+
+protected:
+  [[nodiscard]] auto GetProtoValue() const noexcept -> const ProtoValue * {
+    if (this->proto_value == nullptr) {
+      this->proto_value = Arena::CreateMessage<ProtoValue>(get_arena());
+      this->proto_value->mutable_scalar_value()->CopyFrom(*this->wrapped);
+    }
+    return this->proto_value;
+  };
+  inline ScalarValue() : ProtoMessageWrapper<ProtoScalarValue>(), proto_value(nullptr) {}
+
+private:
+  mutable ProtoValue *proto_value;
 };
 
-class Value : public ProtoMessageWrapper<ProtoValue> {
+class Value : public AbstractValue, public ProtoMessageWrapper<ProtoValue> {
 public:
+  /**
+   * Copy constructor.
+   */
+  inline Value(const Value &original) : Value() { this->wrapped->CopyFrom(*original.wrapped); }
+  /**
+   * Move constructor.
+   */
+  inline Value(Value &&other) : Value(std::move(other.wrapped)) {}
+  /**
+   * Destructor.
+   */
+  inline ~Value() {}
   inline Value() : ProtoMessageWrapper<ProtoValue>() {
     // has NULL_VALUE now
   }
+  explicit inline Value(const ScalarValue &value) : Value() {
+    this->wrapped->mutable_scalar_value()->CopyFrom(*value.wrapped);
+  }
+  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>() {
     this->wrapped->mutable_scalar_value()->set_string_value(value);
@@ -121,7 +321,10 @@ public:
   LIST_VALUE_CONSTRUCTOR(bool, set_boolean_value)
 
   [[nodiscard]] inline auto IsNull() const noexcept -> bool {
-    return this->wrapped->value_case() == ValueCase::VALUE_NOT_SET;
+    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);
   }
 
   [[nodiscard]] inline auto IsString() const noexcept -> bool {
@@ -134,7 +337,7 @@ public:
     }
     return false;
   }
-  [[nodiscard]] inline auto AsString() const noexcept -> const std::string & {
+  [[nodiscard]] inline auto GetAsString() const noexcept -> const std::string & {
     return this->wrapped->scalar_value().string_value();
     ;
   }
@@ -146,18 +349,18 @@ public:
     }
     return false;
   }
-  [[nodiscard]] inline auto AsDouble() const noexcept -> double {
+  [[nodiscard]] inline auto GetAsDouble() const noexcept -> double {
     return this->wrapped->scalar_value().double_value();
   }
 
-  [[nodiscard]] inline auto IsInteger() const noexcept -> bool {
+  [[nodiscard]] inline auto IsInt64() const noexcept -> bool {
     if (this->wrapped->value_case() == ValueCase::kScalarValue) {
 
       return (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kIntegerValue);
     }
     return false;
   }
-  [[nodiscard]] inline auto AsInteger() const noexcept -> int64_t {
+  [[nodiscard]] inline auto GetAsInt64() const noexcept -> int64_t {
     return this->wrapped->scalar_value().integer_value();
   }
 
@@ -168,31 +371,55 @@ public:
     }
     return false;
   }
-  [[nodiscard]] inline auto AsBool() const noexcept -> bool {
+  [[nodiscard]] inline auto GetAsBool() const noexcept -> bool {
     return this->wrapped->scalar_value().boolean_value();
   }
 
-  [[nodiscard]] inline auto IsList() const noexcept -> bool {
+  [[nodiscard]] inline auto IsVector() const noexcept -> bool {
     return this->wrapped->value_case() == ValueCase::kListValues;
   }
-  [[nodiscard]] inline auto AsList() const noexcept -> const std::vector<ScalarValue> & {
-    if (!IsList()) {
+  [[nodiscard]] inline auto GetAsVector() const noexcept -> const std::vector<ScalarValue> & {
+    if (!IsVector()) {
       // create empty list
-      this->list_values = std::make_unique<std::vector<ScalarValue>>();
+      this->collection_values = std::make_unique<std::vector<ScalarValue>>();
     }
-    if (this->list_values == nullptr) {
-      this->list_values = std::make_unique<std::vector<ScalarValue>>();
+    if (this->collection_values == nullptr) {
+      this->collection_values = std::make_unique<std::vector<ScalarValue>>();
       for (auto &scalar : *(this->wrapped->mutable_list_values()->mutable_values())) {
-        this->list_values->push_back(ScalarValue(&scalar));
+        this->collection_values->push_back(ScalarValue(&scalar));
       }
     }
-    return *(this->list_values);
+    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.
+   */
+  inline auto operator=(const Value &other) -> Value & {
+    if (&other != this) {
+      this->wrapped->CopyFrom(*other.wrapped);
+    }
+    return *this;
+  }
+
+  /**
+   * Move assignment operator.
+   */
+  inline auto operator=(Value &&other) -> Value & {
+    if (&other != this) {
+      this->wrapped = std::move(other.wrapped);
+    }
+    return *this;
+  }
+
   inline auto ToString() const noexcept -> const std::string {
     CAOSDB_DEBUG_MESSAGE_STRING(*wrapped, out)
     return out;
@@ -201,8 +428,11 @@ public:
   friend class Entity;
   friend class Property;
 
+protected:
+  [[nodiscard]] auto GetProtoValue() const noexcept -> const ProtoValue * { return this->wrapped; };
+
 private:
-  mutable std::unique_ptr<std::vector<ScalarValue>> list_values;
+  mutable std::unique_ptr<std::vector<ScalarValue>> collection_values;
 };
 
 } // namespace caosdb::entity
diff --git a/include/ccaosdb.h b/include/ccaosdb.h
index 788cf0bdaa49bea9fffa787a66d55d35addbd14a..b9296349b6f9592bed9e60362ae4848faf95a649 100644
--- a/include/ccaosdb.h
+++ b/include/ccaosdb.h
@@ -264,8 +264,6 @@ int caosdb_connection_connection_manager_get_connection(caosdb_connection_connec
  * ENTITY STUFF AND TRANSACTIONS
  ****************************************************************************/
 
-// TODO(fspreck) implementations needed, and probably these declarations are
-// not sufficient yet.
 typedef struct caosdb_transaction_transaction {
   void *wrapped_transaction;
   bool _deletable = false;
@@ -363,33 +361,25 @@ typedef struct caosdb_entity_message {
   bool _deletable = false;
 } caosdb_entity_message;
 
+typedef struct caosdb_entity_value {
+  void *wrapped_value;
+  bool _deletable = false;
+} caosdb_entity_value;
+
+typedef struct caosdb_entity_datatype {
+  void *wrapped_datatype;
+  bool _deletable = false;
+} caosdb_entity_datatype;
+
 // GETTERS FOR EVERYTHING
 int caosdb_entity_entity_get_id(caosdb_entity_entity *entity, char **out);
 int caosdb_entity_entity_get_role(caosdb_entity_entity *entity, char **out);
 int caosdb_entity_entity_get_name(caosdb_entity_entity *entity, char **out);
 int caosdb_entity_entity_get_description(caosdb_entity_entity *entity, char **out);
 int caosdb_entity_entity_get_local_path(caosdb_entity_entity *entity, char **out);
-/**
- * Get the name of the entity's datatype, whether it is a reference, and whether it is a list.
- */
-int caosdb_entity_entity_get_datatype(caosdb_entity_entity *entity, char **name, bool *is_ref,
-                                      bool *is_list);
+int caosdb_entity_entity_get_datatype(caosdb_entity_entity *entity, caosdb_entity_datatype *out);
 int caosdb_entity_entity_get_unit(caosdb_entity_entity *entity, char **out);
-
-int caosdb_entity_entity_get_int_value(caosdb_entity_entity *entity, int64_t *out);
-int caosdb_entity_entity_get_double_value(caosdb_entity_entity *entity, double *out);
-int caosdb_entity_entity_get_boolean_value(caosdb_entity_entity *entity, bool *out);
-int caosdb_entity_entity_get_string_value(caosdb_entity_entity *entity, char **out);
-int caosdb_entity_entity_get_int_list_value_at(caosdb_entity_entity *entity, int64_t *out,
-                                               const int index);
-int caosdb_entity_entity_get_double_list_value_at(caosdb_entity_entity *entity, double *out,
-                                                  const int index);
-int caosdb_entity_entity_get_boolean_list_value_at(caosdb_entity_entity *entity, bool *out,
-                                                   const int index);
-int caosdb_entity_entity_get_string_list_value_at(caosdb_entity_entity *entity, char **out,
-                                                  const int index);
-int caosdb_entity_entity_get_value_list_length(caosdb_entity_entity *entity, int *out);
-
+int caosdb_entity_entity_get_value(caosdb_entity_entity *entity, caosdb_entity_value *out);
 int caosdb_entity_entity_get_version_id(caosdb_entity_entity *entity, char **out);
 int caosdb_entity_entity_get_errors_size(caosdb_entity_entity *entity, int *out);
 int caosdb_entity_entity_get_error(caosdb_entity_entity *entity, caosdb_entity_message *out,
@@ -411,27 +401,10 @@ int caosdb_entity_property_get_id(caosdb_entity_property *property, char **out);
 int caosdb_entity_property_get_name(caosdb_entity_property *property, char **out);
 int caosdb_entity_property_get_description(caosdb_entity_property *property, char **out);
 int caosdb_entity_property_get_importance(caosdb_entity_property *property, char **out);
-/**
- * Get the name of the property's datatype, whether it is a reference, and whether it is a list.
- */
-int caosdb_entity_property_get_datatype(caosdb_entity_property *property, char **name, bool *is_ref,
-                                        bool *is_list);
+int caosdb_entity_property_get_datatype(caosdb_entity_property *property,
+                                        caosdb_entity_datatype *out);
 int caosdb_entity_property_get_unit(caosdb_entity_property *property, char **out);
-
-int caosdb_entity_property_get_int_value(caosdb_entity_property *property, int64_t *out);
-int caosdb_entity_property_get_double_value(caosdb_entity_property *property, double *out);
-int caosdb_entity_property_get_boolean_value(caosdb_entity_property *property, bool *out);
-int caosdb_entity_property_get_string_value(caosdb_entity_property *property, char **out);
-int caosdb_entity_property_get_int_list_value_at(caosdb_entity_property *property, int64_t *out,
-                                                 const int index);
-int caosdb_entity_property_get_double_list_value_at(caosdb_entity_property *property, double *out,
-                                                    const int index);
-int caosdb_entity_property_get_boolean_list_value_at(caosdb_entity_property *property, bool *out,
-                                                     const int index);
-int caosdb_entity_property_get_string_list_value_at(caosdb_entity_property *property, char **out,
-                                                    const int index);
-int caosdb_entity_property_get_value_list_length(caosdb_entity_property *property, int *out);
-
+int caosdb_entity_property_get_value(caosdb_entity_property *property, caosdb_entity_value *out);
 int caosdb_entity_parent_get_id(caosdb_entity_parent *parent, char **out);
 int caosdb_entity_parent_get_name(caosdb_entity_parent *parent, char **out);
 int caosdb_entity_parent_get_description(caosdb_entity_parent *parent, char **out);
@@ -439,6 +412,26 @@ int caosdb_entity_parent_get_description(caosdb_entity_parent *parent, char **ou
 int caosdb_entity_message_get_code(caosdb_entity_message *message, int *out);
 int caosdb_entity_message_get_description(caosdb_entity_message *message, char **out);
 
+int caosdb_entity_datatype_is_atomic(caosdb_entity_datatype *datatype, bool *out);
+int caosdb_entity_datatype_is_reference(caosdb_entity_datatype *datatype, bool *out);
+int caosdb_entity_datatype_is_list_of_atomic(caosdb_entity_datatype *datatype, bool *out);
+int caosdb_entity_datatype_is_list_of_reference(caosdb_entity_datatype *datatype, bool *out);
+int caosdb_entity_datatype_get_datatype_name(caosdb_entity_datatype *datatype, char **out);
+
+int caosdb_entity_value_is_null(caosdb_entity_value *value, bool *out);
+int caosdb_entity_value_is_string(caosdb_entity_value *value, bool *out);
+int caosdb_entity_value_is_double(caosdb_entity_value *value, bool *out);
+int caosdb_entity_value_is_integer(caosdb_entity_value *value, bool *out);
+int caosdb_entity_value_is_bool(caosdb_entity_value *value, bool *out);
+int caosdb_entity_value_is_vector(caosdb_entity_value *value, bool *out);
+int caosdb_entity_value_get_as_string(caosdb_entity_value *value, char **out);
+int caosdb_entity_value_get_as_double(caosdb_entity_value *value, double *out);
+int caosdb_entity_value_get_as_integer(caosdb_entity_value *value, int64_t *out);
+int caosdb_entity_value_get_as_bool(caosdb_entity_value *value, bool *out);
+int caosdb_entity_value_get_as_vector_size(caosdb_entity_value *value, int *out);
+int caosdb_entity_value_get_as_vector_at(caosdb_entity_value *value, caosdb_entity_value *out,
+                                         const int index);
+
 // CONSTRUCTORS AND DESTRUCTORS
 int caosdb_entity_create_entity(caosdb_entity_entity *out);
 int caosdb_entity_delete_entity(caosdb_entity_entity *out);
@@ -447,31 +440,38 @@ int caosdb_entity_delete_property(caosdb_entity_property *out);
 int caosdb_entity_create_parent(caosdb_entity_parent *out);
 int caosdb_entity_delete_parent(caosdb_entity_parent *out);
 
+// DATATYPE CONSTRUCTORS for atomic and reference datatypes and lists thereof
+int caosdb_entity_create_atomic_datatype(caosdb_entity_datatype *out, const char *name);
+int caosdb_entity_create_reference_datatype(caosdb_entity_datatype *out, const char *name);
+int caosdb_entity_create_atomic_list_datatype(caosdb_entity_datatype *out, const char *name);
+int caosdb_entity_create_reference_list_datatype(caosdb_entity_datatype *out, const char *name);
+int caosdb_entity_delete_datatype(caosdb_entity_datatype *out);
+
+// VALUE CONSTRUCTORS (resolve overloaded constructors)
+int caosdb_entity_create_int_value(caosdb_entity_value *out, const int64_t value);
+int caosdb_entity_create_string_value(caosdb_entity_value *out, const char *value);
+int caosdb_entity_create_double_value(caosdb_entity_value *out, const double value);
+int caosdb_entity_create_bool_value(caosdb_entity_value *out, const bool value);
+int caosdb_entity_create_int_vector_value(caosdb_entity_value *out, const int64_t *value,
+                                          const int length);
+int caosdb_entity_create_string_vector_value(caosdb_entity_value *out, const char **value,
+                                             const int length);
+int caosdb_entity_create_double_vector_value(caosdb_entity_value *out, const double *value,
+                                             const int length);
+int caosdb_entity_create_bool_vector_value(caosdb_entity_value *out, const bool *value,
+                                           const int length);
+int caosdb_entity_delete_value(caosdb_entity_value *out);
+
 // SETTERS FOR EVERYTHING THAT MAY BE SET
 int caosdb_entity_entity_set_role(caosdb_entity_entity *entity, const char *role);
 int caosdb_entity_entity_set_name(caosdb_entity_entity *entity, const char *name);
 int caosdb_entity_entity_set_description(caosdb_entity_entity *entity, const char *description);
 int caosdb_entity_entity_set_local_path(caosdb_entity_entity *entity, const char *name);
 int caosdb_entity_entity_set_file_path(caosdb_entity_entity *entity, const char *name);
-/**
- * Set the entity's datatype by name, and whether it is a reference or a list.
- */
-int caosdb_entity_entity_set_datatype(caosdb_entity_entity *entity, const char *datatype,
-                                      const bool is_ref, const bool is_list);
+int caosdb_entity_entity_set_datatype(caosdb_entity_entity *entity,
+                                      caosdb_entity_datatype *datatype);
 int caosdb_entity_entity_set_unit(caosdb_entity_entity *entity, const char *unit);
-// TODO(fspreck) replace by more specific setters
-int caosdb_entity_entity_set_int_value(caosdb_entity_entity *entity, const int64_t value);
-int caosdb_entity_entity_set_double_value(caosdb_entity_entity *entity, const double value);
-int caosdb_entity_entity_set_boolean_value(caosdb_entity_entity *entity, const bool value);
-int caosdb_entity_entity_set_string_value(caosdb_entity_entity *entity, const char *value);
-int caosdb_entity_entity_set_int_list_value(caosdb_entity_entity *entity, const int64_t *value,
-                                            const int length);
-int caosdb_entity_entity_set_double_list_value(caosdb_entity_entity *entity, const double *value,
-                                               const int length);
-int caosdb_entity_entity_set_boolean_list_value(caosdb_entity_entity *entity, const bool *value,
-                                                const int length);
-int caosdb_entity_entity_set_string_list_value(caosdb_entity_entity *entity, const char **value,
-                                               const int length);
+int caosdb_entity_entity_set_value(caosdb_entity_entity *entity, caosdb_entity_value *value);
 
 int caosdb_entity_entity_append_parent(caosdb_entity_entity *entity, caosdb_entity_parent *parent);
 int caosdb_entity_entity_remove_parent(caosdb_entity_entity *entity, int index);
@@ -481,26 +481,11 @@ int caosdb_entity_entity_remove_property(caosdb_entity_entity *entity, int index
 
 int caosdb_entity_property_set_id(caosdb_entity_property *property, const char *id);
 int caosdb_entity_property_set_name(caosdb_entity_property *property, const char *name);
-/**
- * Set the property's datatype by name, and whether it is a reference or a list.
- */
-int caosdb_entity_property_set_datatype(caosdb_entity_property *property, const char *datatype,
-                                        const bool is_ref, const bool is_list);
+int caosdb_entity_property_set_datatype(caosdb_entity_property *property,
+                                        caosdb_entity_datatype *datatype);
 int caosdb_entity_property_set_importance(caosdb_entity_property *property, const char *importance);
 int caosdb_entity_property_set_unit(caosdb_entity_property *property, const char *unit);
-
-int caosdb_entity_property_set_int_value(caosdb_entity_property *property, const int64_t value);
-int caosdb_entity_property_set_double_value(caosdb_entity_property *property, const double value);
-int caosdb_entity_property_set_boolean_value(caosdb_entity_property *property, const bool value);
-int caosdb_entity_property_set_string_value(caosdb_entity_property *property, const char *value);
-int caosdb_entity_property_set_int_list_value(caosdb_entity_property *property,
-                                              const int64_t *value, const int length);
-int caosdb_entity_property_set_double_list_value(caosdb_entity_property *property,
-                                                 const double *value, const int length);
-int caosdb_entity_property_set_boolean_list_value(caosdb_entity_property *property,
-                                                  const bool *value, const int length);
-int caosdb_entity_property_set_string_list_value(caosdb_entity_property *property,
-                                                 const char **value, const int length);
+int caosdb_entity_property_set_value(caosdb_entity_property *property, caosdb_entity_value *value);
 
 int caosdb_entity_parent_set_id(caosdb_entity_parent *parent, const char *id);
 int caosdb_entity_parent_set_name(caosdb_entity_parent *parent, const char *name);
diff --git a/src/caosdb/entity.cpp b/src/caosdb/entity.cpp
index 167e3ae994b3d2b7beaff07f5b09e37eebdb3060..7f241520ac9e29b7c628eb363698a4d365945ea9 100644
--- a/src/caosdb/entity.cpp
+++ b/src/caosdb/entity.cpp
@@ -109,6 +109,8 @@ auto Property::SetImportance(Importance importance) -> void {
 
 auto Property::SetValue(const Value &value) -> StatusCode { return this->value.CopyFrom(value); }
 
+auto Property::SetValue(const AbstractValue &value) -> StatusCode { return SetValue(Value(value)); }
+
 auto Property::SetValue(const std::string &value) -> StatusCode { return SetValue(Value(value)); }
 
 auto Property::SetValue(const char *value) -> StatusCode { return SetValue(Value(value)); }
@@ -203,6 +205,8 @@ auto Entity::SetValue(const Value &value) -> StatusCode {
   return this->value.CopyFrom(value);
 }
 
+auto Entity::SetValue(const AbstractValue &value) -> StatusCode { return SetValue(Value(value)); }
+
 auto Entity::SetValue(const std::string &value) -> StatusCode { return SetValue(Value(value)); }
 
 auto Entity::SetValue(const char *value) -> StatusCode { return SetValue(Value(value)); }
diff --git a/src/ccaosdb.cpp b/src/ccaosdb.cpp
index 2e2a452729518ea5fb4acf125dea24337dc4a0e2..a18c56d90a2b72449ef7fcb60c0dd3e79603dafc 100644
--- a/src/ccaosdb.cpp
+++ b/src/ccaosdb.cpp
@@ -23,6 +23,8 @@
 #include "caosdb/connection.h"
 #include "caosdb/constants.h"
 #include "caosdb/data_type.h" // for DataType, AtomicDat...
+#include "caosdb/entity.h"
+#include "caosdb/value.h"
 #include "caosdb/utility.h"
 #include "caosdb/status_code.h"
 #include "caosdb/logging.h"
@@ -46,12 +48,21 @@ extern "C" {
 
 #define WRAPPED_MESSAGE_CAST(name) static_cast<caosdb::entity::Message *>(name->wrapped_message)
 
+#define WRAPPED_DATATYPE_CAST(name) static_cast<caosdb::entity::DataType *>(name->wrapped_datatype)
+
+#define WRAPPED_VALUE_CAST(name) static_cast<caosdb::entity::AbstractValue *>(name->wrapped_value)
+
 #define ENUM_NAME_FROM_VALUE(arg, etype)                                                           \
   caosdb::utility::getEnumNameFromValue<caosdb::entity::etype>(arg)
 
 #define ENUM_VALUE_FROM_NAME(arg, etype)                                                           \
   caosdb::utility::getEnumValueFromName<caosdb::entity::etype>(arg)
 
+#define RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(name)                                                \
+  if (name->_deletable) {                                                                          \
+    return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR;                                          \
+  }
+
 /*
  * Macro for wrapping every function into a try-catch clause. If an exception
  * occurs, the given StatusCode is being returned.
@@ -146,6 +157,58 @@ extern "C" {
       body_part return 0;                                                                          \
     })
 
+/**
+ * Macro for scalar value creators
+ */
+#define CREATE_VALUE(fname, arg)                                                                   \
+  ERROR_RETURN_CODE(GENERIC_ERROR,                                                                 \
+                    int caosdb_entity_create_##fname(caosdb_entity_value *out, arg), {             \
+                      RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out)                                   \
+                      out->wrapped_value = new caosdb::entity::Value(value);                       \
+                      out->_deletable = true;                                                      \
+                      return 0;                                                                    \
+                    })
+/**
+ * Macro for list-value creators
+ */
+#define CREATE_VECTOR_VALUE(fname, type, arg, assign)                                              \
+  ERROR_RETURN_CODE(                                                                               \
+    GENERIC_ERROR,                                                                                 \
+    int caosdb_entity_create_##fname(caosdb_entity_value *out, arg, const int length), {           \
+      if (out->_deletable) {                                                                       \
+        return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR;                                      \
+      }                                                                                            \
+      std::vector<type> value_vec;                                                                 \
+      for (int i = 0; i < length; i++) {                                                           \
+        value_vec.push_back(assign);                                                               \
+      }                                                                                            \
+      out->wrapped_value = new caosdb::entity::Value(value_vec);                                   \
+      out->_deletable = true;                                                                      \
+      return 0;                                                                                    \
+    })
+
+/**
+ * Macro for value is-a functions
+ */
+#define VALUE_IS(fname, isfunction)                                                                \
+  ERROR_RETURN_CODE(GENERIC_ERROR,                                                                 \
+                    int caosdb_entity_value_is_##fname(caosdb_entity_value *value, bool *out), {   \
+                      auto *wrapped_value = WRAPPED_VALUE_CAST(value);                             \
+                      *out = wrapped_value->isfunction();                                          \
+                      return 0;                                                                    \
+                    })
+
+/**
+ * Macro for some value getters
+ */
+#define VALUE_GET_AS(fname, getfunction, arg)                                                      \
+  ERROR_RETURN_CODE(GENERIC_ERROR,                                                                 \
+                    int caosdb_entity_value_get_as_##fname(caosdb_entity_value *value, arg), {     \
+                      auto *wrapped_value = WRAPPED_VALUE_CAST(value);                             \
+                      *out = wrapped_value->getfunction();                                         \
+                      return 0;                                                                    \
+                    })
+
 int caosdb_constants_LIBCAOSDB_VERSION_MAJOR() { return caosdb::LIBCAOSDB_VERSION_MAJOR; }
 
 int caosdb_constants_LIBCAOSDB_VERSION_MINOR() { return caosdb::LIBCAOSDB_VERSION_MINOR; }
@@ -625,139 +688,125 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_delete_parent(caosdb_entity_p
   return 0;
 })
 
-CAOSDB_ENTITY_GET(id, GetId())
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_get_role(caosdb_entity_entity *entity, char **out), {
-                    auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
-                    std::string role_str = ENUM_NAME_FROM_VALUE(wrapped_entity->GetRole(), Role);
-                    auto *tmp = (char *)malloc(sizeof(char) * role_str.length() + 1);
-                    strcpy(tmp, role_str.c_str());
-                    delete[] * out;
-                    *out = tmp;
-                    return 0;
-                  })
-CAOSDB_ENTITY_GET(name, GetName())
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_get_local_path(caosdb_entity_entity *entity, char **out),
+                  int caosdb_entity_create_atomic_datatype(caosdb_entity_datatype *out,
+                                                           const char *name),
                   {
-                    auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
-                    auto path = wrapped_entity->GetLocalPath().string();
-                    auto *tmp = (char *)(malloc(sizeof(char) * path.length() + 1));
-                    strcpy(tmp, path.c_str());
-                    delete[] * out;
-                    *out = tmp;
-                    return 0;
-                  })
-// CAOSDB_ENTITY_GET(file_path, GetFilePath()) TODO(henrik)
-CAOSDB_ENTITY_GET(description, GetDescription())
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_get_datatype(caosdb_entity_entity *entity, char **name,
-                                                        bool *is_ref, bool *is_list),
-                  {
-                    auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
-                    const auto &datatype = wrapped_entity->GetDataType();
-                    *is_list = datatype.IsList();
-                    std::string datatype_name;
-                    if (*is_list) {
-                      const auto &list_datatype = datatype.AsList();
-                      *is_ref = list_datatype.IsListOfReference();
-                      if (*is_ref) {
-                        datatype_name = list_datatype.GetReferenceDataType().GetName();
-                      } else {
-                        datatype_name =
-                          ENUM_NAME_FROM_VALUE(list_datatype.GetAtomicDataType(), AtomicDataType);
-                      }
-                    } else {
-                      *is_ref = datatype.IsReference();
-                      if (*is_ref) {
-                        datatype_name = datatype.AsReference().GetName();
-                      } else {
-                        datatype_name = ENUM_NAME_FROM_VALUE(datatype.AsAtomic(), AtomicDataType);
-                      }
+                    RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out)
+                    try {
+                      auto enum_value = ENUM_VALUE_FROM_NAME(std::string(name), AtomicDataType);
+                      out->wrapped_datatype = new caosdb::entity::DataType(enum_value);
+                      out->_deletable = true;
+                      return 0;
+                    } catch (const std::out_of_range &exc) {
+                      caosdb::logging::caosdb_log_fatal(CCAOSDB_LOGGER_NAME, exc.what());
+                      return caosdb::StatusCode::ENUM_MAPPING_ERROR;
                     }
-                    char *tmp = (char *)malloc(sizeof(char) * datatype_name.length() + 1);
-                    strcpy(tmp, datatype_name.c_str());
-                    delete[] * name;
-                    *name = tmp;
-                    return 0;
                   })
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_get_int_value(caosdb_entity_entity *entity,
-                                                         int64_t *out),
+                  int caosdb_entity_create_reference_datatype(caosdb_entity_datatype *out,
+                                                              const char *name),
                   {
-                    auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
-                    *out = wrapped_entity->GetValue().AsInteger();
+                    RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out)
+                    out->wrapped_datatype = new caosdb::entity::DataType(std::string(name));
+                    out->_deletable = true;
                     return 0;
                   })
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_get_double_value(caosdb_entity_entity *entity,
-                                                            double *out),
+                  int caosdb_entity_create_atomic_list_datatype(caosdb_entity_datatype *out,
+                                                                const char *name),
                   {
-                    auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
-                    *out = wrapped_entity->GetValue().AsDouble();
-                    return 0;
+                    RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out)
+                    try {
+                      auto enum_value = ENUM_VALUE_FROM_NAME(std::string(name), AtomicDataType);
+                      out->wrapped_datatype =
+                        new caosdb::entity::DataType(caosdb::entity::DataType::ListOf(enum_value));
+                      out->_deletable = true;
+                      return 0;
+                    } catch (const std::out_of_range &exc) {
+                      caosdb::logging::caosdb_log_fatal(CCAOSDB_LOGGER_NAME, exc.what());
+                      return caosdb::StatusCode::ENUM_MAPPING_ERROR;
+                    }
                   })
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_get_boolean_value(caosdb_entity_entity *entity,
-                                                             bool *out),
+                  int caosdb_entity_create_reference_list_datatype(caosdb_entity_datatype *out,
+                                                                   const char *name),
                   {
-                    auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
-                    *out = wrapped_entity->GetValue().AsBool();
+                    RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out)
+                    out->wrapped_datatype = new caosdb::entity::DataType(
+                      caosdb::entity::DataType::ListOf(std::string(name)));
+                    out->_deletable = true;
                     return 0;
                   })
-CAOSDB_ENTITY_GET(string_value, GetValue().AsString())
 
+ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_delete_datatype(caosdb_entity_datatype *out), {
+  if (out->_deletable) {
+    delete WRAPPED_DATATYPE_CAST(out);
+  }
+  out->_deletable = false;
+  return 0;
+})
+
+CREATE_VALUE(int_value, const int64_t value)
+CREATE_VALUE(string_value, const char *value)
+CREATE_VALUE(double_value, const double value)
+CREATE_VALUE(bool_value, const bool value)
+CREATE_VECTOR_VALUE(int_vector_value, int64_t, const int64_t *value, value[i])
+CREATE_VECTOR_VALUE(string_vector_value, std::string, const char **value, std::string(value[i]))
+CREATE_VECTOR_VALUE(double_vector_value, double, const double *value, value[i])
+CREATE_VECTOR_VALUE(bool_vector_value, bool, const bool *value, value[i])
+
+ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_delete_value(caosdb_entity_value *out), {
+  if (out->_deletable) {
+    delete WRAPPED_VALUE_CAST(out);
+  }
+  out->_deletable = false;
+  return 0;
+})
+
+CAOSDB_ENTITY_GET(id, GetId())
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_get_int_list_value_at(caosdb_entity_entity *entity,
-                                                                 int64_t *out, const int index),
-                  {
-                    auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
-                    auto value_list = wrapped_entity->GetValue().AsList();
-                    *out = value_list[index].AsInteger();
-                    return 0;
-                  })
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_get_double_list_value_at(caosdb_entity_entity *entity,
-                                                                    double *out, const int index),
-                  {
+                  int caosdb_entity_entity_get_role(caosdb_entity_entity *entity, char **out), {
                     auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
-                    auto value_list = wrapped_entity->GetValue().AsList();
-                    *out = value_list[index].AsDouble();
+                    std::string role_str = ENUM_NAME_FROM_VALUE(wrapped_entity->GetRole(), Role);
+                    auto *tmp = (char *)malloc(sizeof(char) * role_str.length() + 1);
+                    strcpy(tmp, role_str.c_str());
+                    delete[] * out;
+                    *out = tmp;
                     return 0;
                   })
+CAOSDB_ENTITY_GET(name, GetName())
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_get_boolean_list_value_at(caosdb_entity_entity *entity,
-                                                                     bool *out, const int index),
+                  int caosdb_entity_entity_get_local_path(caosdb_entity_entity *entity, char **out),
                   {
                     auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
-                    auto value_list = wrapped_entity->GetValue().AsList();
-                    *out = value_list[index].AsBool();
+                    auto path = wrapped_entity->GetLocalPath().string();
+                    auto *tmp = (char *)(malloc(sizeof(char) * path.length() + 1));
+                    strcpy(tmp, path.c_str());
+                    delete[] * out;
+                    *out = tmp;
                     return 0;
                   })
+// CAOSDB_ENTITY_GET(file_path, GetFilePath()) TODO(henrik)
+CAOSDB_ENTITY_GET(description, GetDescription())
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_get_string_list_value_at(caosdb_entity_entity *entity,
-                                                                    char **out, const int index),
+                  int caosdb_entity_entity_get_datatype(caosdb_entity_entity *entity,
+                                                        caosdb_entity_datatype *out),
                   {
+                    RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out)
                     auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
-                    auto value_list = wrapped_entity->GetValue().AsList();
-                    char *tmp =
-                      (char *)malloc(sizeof(char) * value_list[index].AsString().length() + 1);
-                    strcpy(tmp, value_list[index].AsString().c_str());
-                    delete[] * out;
-                    *out = tmp;
+                    out->wrapped_datatype = (void *)(&(wrapped_entity->GetDataType()));
+                    out->_deletable = false;
                     return 0;
                   })
-
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_get_value_list_length(caosdb_entity_entity *entity,
-                                                                 int *out),
+                  int caosdb_entity_entity_get_value(caosdb_entity_entity *entity,
+                                                     caosdb_entity_value *out),
                   {
+                    RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out)
                     auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
-                    if (wrapped_entity->GetValue().IsList()) {
-                      *out = wrapped_entity->GetValue().AsList().size();
-                    } else {
-                      *out = 0;
-                    }
+                    out->wrapped_value = (void *)(&(wrapped_entity->GetValue()));
+                    out->_deletable = false;
                     return 0;
                   })
 
@@ -901,140 +950,148 @@ ERROR_RETURN_CODE(GENERIC_ERROR,
                     *out = tmp;
                     return 0;
                   })
-
 ERROR_RETURN_CODE(GENERIC_ERROR,
                   int caosdb_entity_property_get_datatype(caosdb_entity_property *property,
-                                                          char **name, bool *is_ref, bool *is_list),
+                                                          caosdb_entity_datatype *out),
                   {
+                    RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out)
                     auto *wrapped_property = WRAPPED_PROPERTY_CAST(property);
-                    const auto &datatype = wrapped_property->GetDataType();
-                    *is_list = datatype.IsList();
-                    std::string datatype_name;
-                    if (*is_list) {
-                      const auto &list_datatype = datatype.AsList();
-                      *is_ref = list_datatype.IsListOfReference();
-                      if (*is_ref) {
-                        datatype_name = list_datatype.GetReferenceDataType().GetName();
-                      } else {
-                        datatype_name =
-                          ENUM_NAME_FROM_VALUE(list_datatype.GetAtomicDataType(), AtomicDataType);
-                      }
-                    } else {
-                      *is_ref = datatype.IsReference();
-                      if (*is_ref) {
-                        datatype_name = datatype.AsReference().GetName();
-                      } else {
-                        datatype_name = ENUM_NAME_FROM_VALUE(datatype.AsAtomic(), AtomicDataType);
-                      }
-                    }
-                    char *tmp = (char *)malloc(sizeof(char) * datatype_name.length() + 1);
-                    strcpy(tmp, datatype_name.c_str());
-                    delete[] * name;
-                    *name = tmp;
+                    out->wrapped_datatype = (void *)(&(wrapped_property->GetDataType()));
+                    out->_deletable = false;
                     return 0;
                   })
-
-CAOSDB_PROPERTY_GET(unit, GetUnit())
-
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_get_int_value(caosdb_entity_property *property,
-                                                           int64_t *out),
+                  int caosdb_entity_property_get_value(caosdb_entity_property *property,
+                                                       caosdb_entity_value *out),
                   {
+                    RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out)
                     auto *wrapped_property = WRAPPED_PROPERTY_CAST(property);
-                    *out = wrapped_property->GetValue().AsInteger();
+                    out->wrapped_value = (void *)(&(wrapped_property->GetValue()));
+                    out->_deletable = false;
                     return 0;
                   })
+CAOSDB_PROPERTY_GET(unit, GetUnit())
+
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_get_double_value(caosdb_entity_property *property,
-                                                              double *out),
-                  {
-                    auto *wrapped_property = WRAPPED_PROPERTY_CAST(property);
-                    *out = wrapped_property->GetValue().AsDouble();
+                  int caosdb_entity_message_get_code(caosdb_entity_message *message, int *out), {
+                    auto *wrapped_message =
+                      static_cast<caosdb::entity::Message *>(message->wrapped_message);
+                    *out = wrapped_message->GetCode();
                     return 0;
                   })
+
+ERROR_RETURN_CODE(
+  GENERIC_ERROR,
+  int caosdb_entity_message_get_description(caosdb_entity_message *message, char **out), {
+    auto *wrapped_message = static_cast<caosdb::entity::Message *>(message->wrapped_message);
+    auto *tmp = (char *)malloc(sizeof(char) * wrapped_message->GetDescription().length() + 1);
+    strcpy(tmp, wrapped_message->GetDescription().c_str());
+    delete[] * out;
+    *out = tmp;
+    return 0;
+  })
+
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_get_boolean_value(caosdb_entity_property *property,
-                                                               bool *out),
+                  int caosdb_entity_datatype_is_atomic(caosdb_entity_datatype *datatype, bool *out),
                   {
-                    auto *wrapped_property = WRAPPED_PROPERTY_CAST(property);
-                    *out = wrapped_property->GetValue().AsBool();
+                    auto *wrapped_datatype = WRAPPED_DATATYPE_CAST(datatype);
+                    *out = wrapped_datatype->IsAtomic();
                     return 0;
                   })
-CAOSDB_PROPERTY_GET(string_value, GetValue().AsString())
-
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_get_int_list_value_at(caosdb_entity_property *property,
-                                                                   int64_t *out, const int index),
+                  int caosdb_entity_datatype_is_reference(caosdb_entity_datatype *datatype,
+                                                          bool *out),
                   {
-                    auto *wrapped_property = WRAPPED_PROPERTY_CAST(property);
-                    auto value_list = wrapped_property->GetValue().AsList();
-                    *out = value_list[index].AsInteger();
+                    auto *wrapped_datatype = WRAPPED_DATATYPE_CAST(datatype);
+                    *out = wrapped_datatype->IsReference();
                     return 0;
                   })
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_get_double_list_value_at(
-                    caosdb_entity_property *property, double *out, const int index),
+                  int caosdb_entity_datatype_is_list_of_atomic(caosdb_entity_datatype *datatype,
+                                                               bool *out),
                   {
-                    auto *wrapped_property = WRAPPED_PROPERTY_CAST(property);
-                    auto value_list = wrapped_property->GetValue().AsList();
-                    *out = value_list[index].AsDouble();
+                    auto *wrapped_datatype = WRAPPED_DATATYPE_CAST(datatype);
+                    if (wrapped_datatype->IsList()) {
+                      const auto &list_datatype = wrapped_datatype->GetAsList();
+                      *out = list_datatype.IsListOfAtomic();
+                    } else {
+                      *out = false;
+                    }
                     return 0;
                   })
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_get_boolean_list_value_at(
-                    caosdb_entity_property *property, bool *out, const int index),
+                  int caosdb_entity_datatype_is_list_of_reference(caosdb_entity_datatype *datatype,
+                                                                  bool *out),
                   {
-                    auto *wrapped_property = WRAPPED_PROPERTY_CAST(property);
-                    auto value_list = wrapped_property->GetValue().AsList();
-                    *out = value_list[index].AsBool();
+                    auto *wrapped_datatype = WRAPPED_DATATYPE_CAST(datatype);
+                    if (wrapped_datatype->IsList()) {
+                      const auto &list_datatype = wrapped_datatype->GetAsList();
+                      *out = list_datatype.IsListOfReference();
+                    } else {
+                      *out = false;
+                    }
                     return 0;
                   })
+ERROR_RETURN_CODE(
+  GENERIC_ERROR,
+  int caosdb_entity_datatype_get_datatype_name(caosdb_entity_datatype *datatype, char **out), {
+    auto *wrapped_datatype = WRAPPED_DATATYPE_CAST(datatype);
+    std::string datatype_name;
+    if (wrapped_datatype->IsList()) {
+      const auto &list_datatype = wrapped_datatype->GetAsList();
+      if (list_datatype.IsListOfAtomic()) {
+        datatype_name = ENUM_NAME_FROM_VALUE(list_datatype.GetAtomicDataType(), AtomicDataType);
+      } else {
+        datatype_name = list_datatype.GetReferenceDataType().GetName();
+      }
+    } else {
+      if (wrapped_datatype->IsAtomic()) {
+        datatype_name = ENUM_NAME_FROM_VALUE(wrapped_datatype->GetAsAtomic(), AtomicDataType);
+      } else {
+        datatype_name = wrapped_datatype->GetAsReference().GetName();
+      }
+    }
+    char *tmp = (char *)malloc(sizeof(char) * datatype_name.length() + 1);
+    strcpy(tmp, datatype_name.c_str());
+    delete[] * out;
+    *out = tmp;
+    return 0;
+  })
+
+VALUE_IS(null, IsNull)
+VALUE_IS(string, IsString)
+VALUE_IS(double, IsDouble)
+VALUE_IS(integer, IsInt64)
+VALUE_IS(bool, IsBool)
+VALUE_IS(vector, IsVector)
+
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_get_string_list_value_at(
-                    caosdb_entity_property *property, char **out, const int index),
-                  {
-                    auto *wrapped_property = WRAPPED_PROPERTY_CAST(property);
-                    auto value_list = wrapped_property->GetValue().AsList();
+                  int caosdb_entity_value_get_as_string(caosdb_entity_value *value, char **out), {
+                    auto *wrapped_value = WRAPPED_VALUE_CAST(value);
                     auto *tmp =
-                      (char *)malloc(sizeof(char) * value_list[index].AsString().length() + 1);
-                    strcpy(tmp, value_list[index].AsString().c_str());
+                      (char *)malloc(sizeof(char) * wrapped_value->GetAsString().length() + 1);
+                    strcpy(tmp, wrapped_value->GetAsString().c_str());
                     delete[] * out;
                     *out = tmp;
                     return 0;
                   })
-
+VALUE_GET_AS(double, GetAsDouble, double *out)
+VALUE_GET_AS(integer, GetAsInt64, int64_t *out)
+VALUE_GET_AS(bool, GetAsBool, bool *out)
+VALUE_GET_AS(vector_size, GetAsVector().size, int *out)
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_get_value_list_length(caosdb_entity_property *property,
-                                                                   int *out),
+                  int caosdb_entity_value_get_as_vector_at(caosdb_entity_value *value,
+                                                           caosdb_entity_value *out,
+                                                           const int index),
                   {
-                    auto *wrapped_property = WRAPPED_PROPERTY_CAST(property);
-                    if (wrapped_property->GetValue().IsList()) {
-                      *out = wrapped_property->GetValue().AsList().size();
-                    } else {
-                      *out = 0;
+                    if (out->_deletable) {
+                      return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR;
                     }
+                    auto *wrapped_value = WRAPPED_VALUE_CAST(value);
+                    out->wrapped_value = (void *)(&(wrapped_value->GetAsVector().at(index)));
+                    out->_deletable = false;
                     return 0;
                   })
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_message_get_code(caosdb_entity_message *message, int *out), {
-                    auto *wrapped_message =
-                      static_cast<caosdb::entity::Message *>(message->wrapped_message);
-                    *out = wrapped_message->GetCode();
-                    return 0;
-                  })
-
-ERROR_RETURN_CODE(
-  GENERIC_ERROR,
-  int caosdb_entity_message_get_description(caosdb_entity_message *message, char **out), {
-    auto *wrapped_message = static_cast<caosdb::entity::Message *>(message->wrapped_message);
-    auto *tmp = (char *)malloc(sizeof(char) * wrapped_message->GetDescription().length() + 1);
-    strcpy(tmp, wrapped_message->GetDescription().c_str());
-    delete[] * out;
-    *out = tmp;
-    return 0;
-  })
-
 ERROR_RETURN_CODE(GENERIC_ERROR,
                   int caosdb_entity_entity_set_role(caosdb_entity_entity *entity, const char *role),
                   {
@@ -1054,129 +1111,24 @@ CAOSDB_ENTITY_SET(local_path, local_path,
 CAOSDB_ENTITY_SET(file_path, file_path, wrapped_entity->SetFilePath(std::string(file_path));)
 CAOSDB_ENTITY_SET(description, description,
                   wrapped_entity->SetDescription(std::string(description));)
+CAOSDB_ENTITY_SET(unit, unit, wrapped_entity->SetUnit(std::string(unit));)
 ERROR_RETURN_CODE(GENERIC_ERROR,
                   int caosdb_entity_entity_set_datatype(caosdb_entity_entity *entity,
-                                                        const char *datatype, const bool is_ref,
-                                                        const bool is_list),
+                                                        caosdb_entity_datatype *datatype),
                   {
                     auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
-                    if (is_ref) {
-                      // Refernce datatype with name of reference
-                      wrapped_entity->SetDataType(std::string(datatype), is_list);
-                      return 0;
-                    } else {
-                      // Atomic datatype so get from enum
-                      try {
-                        auto enum_value =
-                          ENUM_VALUE_FROM_NAME(std::string(datatype), AtomicDataType);
-                        wrapped_entity->SetDataType(enum_value, is_list);
-                        return 0;
-                      } catch (const std::out_of_range &exc) {
-                        caosdb::logging::caosdb_log_fatal(CCAOSDB_LOGGER_NAME, exc.what());
-                        return caosdb::StatusCode::ENUM_MAPPING_ERROR;
-                      }
-                    }
-                  })
-CAOSDB_ENTITY_SET(unit, unit, wrapped_entity->SetUnit(std::string(unit));)
+                    auto *wrapped_datatype = WRAPPED_DATATYPE_CAST(datatype);
 
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_set_int_value(caosdb_entity_entity *entity,
-                                                         const int64_t value),
-                  {
-                    auto *wrapped_entity =
-                      static_cast<caosdb::entity::Entity *>(entity->wrapped_entity);
-                    wrapped_entity->SetValue(value);
-                    return 0;
+                    return wrapped_entity->SetDataType(*wrapped_datatype);
                   })
-
 ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_set_double_value(caosdb_entity_entity *entity,
-                                                            const double value),
+                  int caosdb_entity_entity_set_value(caosdb_entity_entity *entity,
+                                                     caosdb_entity_value *value),
                   {
-                    auto *wrapped_entity =
-                      static_cast<caosdb::entity::Entity *>(entity->wrapped_entity);
-                    wrapped_entity->SetValue(value);
-                    return 0;
-                  })
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_set_boolean_value(caosdb_entity_entity *entity,
-                                                             const bool value),
-                  {
-                    auto *wrapped_entity =
-                      static_cast<caosdb::entity::Entity *>(entity->wrapped_entity);
-                    wrapped_entity->SetValue(value);
-                    return 0;
-                  })
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_set_string_value(caosdb_entity_entity *entity,
-                                                            const char *value),
-                  {
-                    auto *wrapped_entity =
-                      static_cast<caosdb::entity::Entity *>(entity->wrapped_entity);
-                    wrapped_entity->SetValue(std::string(value));
-                    return 0;
-                  })
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_set_int_list_value(caosdb_entity_entity *entity,
-                                                              const int64_t *value,
-                                                              const int length),
-                  {
-                    auto *wrapped_entity =
-                      static_cast<caosdb::entity::Entity *>(entity->wrapped_entity);
-                    std::vector<int64_t> value_list;
-                    for (int i = 0; i < length; i++) {
-                      value_list.push_back(value[i]);
-                    }
-                    wrapped_entity->SetValue(value_list);
-                    return 0;
-                  })
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_set_double_list_value(caosdb_entity_entity *entity,
-                                                                 const double *value,
-                                                                 const int length),
-                  {
-                    auto *wrapped_entity =
-                      static_cast<caosdb::entity::Entity *>(entity->wrapped_entity);
-                    std::vector<double> value_list;
-                    for (int i = 0; i < length; i++) {
-                      value_list.push_back(value[i]);
-                    }
-                    wrapped_entity->SetValue(value_list);
-                    return 0;
-                  })
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_set_boolean_list_value(caosdb_entity_entity *entity,
-                                                                  const bool *value,
-                                                                  const int length),
-                  {
-                    auto *wrapped_entity =
-                      static_cast<caosdb::entity::Entity *>(entity->wrapped_entity);
-                    std::vector<bool> value_list;
-                    for (int i = 0; i < length; i++) {
-                      value_list.push_back(value[i]);
-                    }
-                    wrapped_entity->SetValue(value_list);
-                    return 0;
-                  })
+                    auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity);
+                    auto *wrapped_value = WRAPPED_VALUE_CAST(value);
 
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_entity_set_string_list_value(caosdb_entity_entity *entity,
-                                                                 const char **value,
-                                                                 const int length),
-                  {
-                    auto *wrapped_entity =
-                      static_cast<caosdb::entity::Entity *>(entity->wrapped_entity);
-                    std::vector<std::string> value_list;
-                    for (int i = 0; i < length; i++) {
-                      value_list.push_back(std::string(value[i]));
-                    }
-                    wrapped_entity->SetValue(value_list);
-                    return 0;
+                    return wrapped_entity->SetValue(*wrapped_value);
                   })
 
 ERROR_RETURN_CODE(GENERIC_ERROR,
@@ -1224,29 +1176,23 @@ CAOSDB_PARENT_SET(name, name, wrapped_parent->SetName(std::string(name));)
 
 CAOSDB_PROPERTY_SET(name, name, wrapped_property->SetName(std::string(name));)
 CAOSDB_PROPERTY_SET(id, id, wrapped_property->SetId(std::string(id));)
-
 ERROR_RETURN_CODE(GENERIC_ERROR,
                   int caosdb_entity_property_set_datatype(caosdb_entity_property *property,
-                                                          const char *datatype, const bool is_ref,
-                                                          const bool is_list),
+                                                          caosdb_entity_datatype *datatype),
                   {
                     auto *wrapped_property = WRAPPED_PROPERTY_CAST(property);
-                    if (is_ref) {
-                      // Refernce datatype with name of reference
-                      wrapped_property->SetDataType(std::string(datatype), is_list);
-                      return 0;
-                    } else {
-                      // Atomic datatype so get from enum
-                      try {
-                        auto enum_value =
-                          ENUM_VALUE_FROM_NAME(std::string(datatype), AtomicDataType);
-                        wrapped_property->SetDataType(enum_value, is_list);
-                        return 0;
-                      } catch (const std::out_of_range &exc) {
-                        caosdb::logging::caosdb_log_fatal(CCAOSDB_LOGGER_NAME, exc.what());
-                        return caosdb::StatusCode::ENUM_MAPPING_ERROR;
-                      }
-                    }
+                    auto *wrapped_datatype = WRAPPED_DATATYPE_CAST(datatype);
+
+                    return wrapped_property->SetDataType(*wrapped_datatype);
+                  })
+ERROR_RETURN_CODE(GENERIC_ERROR,
+                  int caosdb_entity_property_set_value(caosdb_entity_property *property,
+                                                       caosdb_entity_value *value),
+                  {
+                    auto *wrapped_property = WRAPPED_PROPERTY_CAST(property);
+                    auto *wrapped_value = WRAPPED_VALUE_CAST(value);
+
+                    return wrapped_property->SetValue(*wrapped_value);
                   })
 
 ERROR_RETURN_CODE(GENERIC_ERROR,
@@ -1265,103 +1211,4 @@ ERROR_RETURN_CODE(GENERIC_ERROR,
                   })
 
 CAOSDB_PROPERTY_SET(unit, unit, wrapped_property->SetUnit(std::string(unit));)
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_set_int_value(caosdb_entity_property *property,
-                                                           const int64_t value),
-                  {
-                    auto *wrapped_property =
-                      static_cast<caosdb::entity::Property *>(property->wrapped_property);
-                    wrapped_property->SetValue(value);
-                    return 0;
-                  })
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_set_double_value(caosdb_entity_property *property,
-                                                              const double value),
-                  {
-                    auto *wrapped_property =
-                      static_cast<caosdb::entity::Property *>(property->wrapped_property);
-                    wrapped_property->SetValue(value);
-                    return 0;
-                  })
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_set_boolean_value(caosdb_entity_property *property,
-                                                               const bool value),
-                  {
-                    auto *wrapped_property =
-                      static_cast<caosdb::entity::Property *>(property->wrapped_property);
-                    wrapped_property->SetValue(value);
-                    return 0;
-                  })
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_set_string_value(caosdb_entity_property *property,
-                                                              const char *value),
-                  {
-                    auto *wrapped_property =
-                      static_cast<caosdb::entity::Property *>(property->wrapped_property);
-                    wrapped_property->SetValue(std::string(value));
-                    return 0;
-                  })
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_set_int_list_value(caosdb_entity_property *property,
-                                                                const int64_t *value,
-                                                                const int length),
-                  {
-                    auto *wrapped_property =
-                      static_cast<caosdb::entity::Property *>(property->wrapped_property);
-                    std::vector<int64_t> value_list;
-                    for (int i = 0; i < length; i++) {
-                      value_list.push_back(value[i]);
-                    }
-                    wrapped_property->SetValue(value_list);
-                    return 0;
-                  })
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_set_double_list_value(caosdb_entity_property *property,
-                                                                   const double *value,
-                                                                   const int length),
-                  {
-                    auto *wrapped_property =
-                      static_cast<caosdb::entity::Property *>(property->wrapped_property);
-                    std::vector<double> value_list;
-                    for (int i = 0; i < length; i++) {
-                      value_list.push_back(value[i]);
-                    }
-                    wrapped_property->SetValue(value_list);
-                    return 0;
-                  })
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_set_boolean_list_value(
-                    caosdb_entity_property *property, const bool *value, const int length),
-                  {
-                    auto *wrapped_property =
-                      static_cast<caosdb::entity::Property *>(property->wrapped_property);
-                    std::vector<bool> value_list;
-                    for (int i = 0; i < length; i++) {
-                      value_list.push_back(value[i]);
-                    }
-                    wrapped_property->SetValue(value_list);
-                    return 0;
-                  })
-
-ERROR_RETURN_CODE(GENERIC_ERROR,
-                  int caosdb_entity_property_set_string_list_value(caosdb_entity_property *property,
-                                                                   const char **value,
-                                                                   const int length),
-                  {
-                    auto *wrapped_property =
-                      static_cast<caosdb::entity::Property *>(property->wrapped_property);
-                    std::vector<std::string> value_list;
-                    for (int i = 0; i < length; i++) {
-                      value_list.push_back(std::string(value[i]));
-                    }
-                    wrapped_property->SetValue(value_list);
-                    return 0;
-                  })
 }
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 6049d0fa369c8e6c2a95bec554c0946e5a2b4aa3..aefe6846d23f2cc3a145cbf6158101e7e1bb3df4 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -61,6 +61,7 @@ foreach (i RANGE "${len_test_cases}")
     target_include_directories(${test_case_name}
       PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
     if(_LINTING)
+        message(STATUS "linting for tests: ${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE}")
         set_target_properties(${test_case_name}
             PROPERTIES
             CXX_CLANG_TIDY "${_CMAKE_CXX_CLANG_TIDY};${_CMAKE_CXX_CLANG_TIDY_TEST_CHECKS}"
diff --git a/test/test_ccaosdb.cpp b/test/test_ccaosdb.cpp
index cbf595f821f45807d8dd780cadd94bde47544fe8..361b0918060e46cf71b435e519b3a7ec20b1ee46 100644
--- a/test/test_ccaosdb.cpp
+++ b/test/test_ccaosdb.cpp
@@ -127,6 +127,255 @@ TEST_F(test_ccaosdb, test_query) {
   EXPECT_EQ(return_code, 0);
 }
 
+TEST_F(test_ccaosdb, test_datatype) {
+
+  caosdb_entity_datatype atomic;
+  // check that this fails
+  int return_code(caosdb_entity_create_atomic_datatype(&atomic, "some type"));
+  EXPECT_EQ(return_code, caosdb::StatusCode::ENUM_MAPPING_ERROR);
+
+  return_code = caosdb_entity_create_atomic_datatype(&atomic, "INTEGER");
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_entity_datatype reference;
+  return_code = caosdb_entity_create_reference_datatype(&reference, "MyType");
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_entity_datatype list_of_atomics;
+  return_code = caosdb_entity_create_atomic_list_datatype(&list_of_atomics, "DATETIME");
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_entity_datatype list_of_references;
+  return_code = caosdb_entity_create_reference_list_datatype(&list_of_references, "MyType");
+  EXPECT_EQ(return_code, 0);
+
+  bool is_a(false);
+  return_code = caosdb_entity_datatype_is_atomic(&atomic, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_TRUE(is_a);
+  return_code = caosdb_entity_datatype_is_reference(&atomic, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_list_of_atomic(&atomic, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_list_of_reference(&atomic, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+
+  return_code = caosdb_entity_datatype_is_atomic(&reference, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_reference(&reference, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_TRUE(is_a);
+  return_code = caosdb_entity_datatype_is_list_of_atomic(&reference, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_list_of_reference(&reference, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+
+  return_code = caosdb_entity_datatype_is_atomic(&list_of_atomics, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_reference(&list_of_atomics, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_list_of_atomic(&list_of_atomics, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_TRUE(is_a);
+  return_code = caosdb_entity_datatype_is_list_of_reference(&list_of_atomics, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+
+  return_code = caosdb_entity_datatype_is_atomic(&list_of_references, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_reference(&list_of_references, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_list_of_atomic(&list_of_references, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_list_of_reference(&list_of_references, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_TRUE(is_a);
+
+  char *name = nullptr; // NOLINT
+  return_code = caosdb_entity_datatype_get_datatype_name(&atomic, &name);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_STREQ(name, "INTEGER");
+
+  return_code = caosdb_entity_datatype_get_datatype_name(&reference, &name);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_STREQ(name, "MyType");
+
+  return_code = caosdb_entity_datatype_get_datatype_name(&list_of_atomics, &name);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_STREQ(name, "DATETIME");
+
+  return_code = caosdb_entity_datatype_get_datatype_name(&list_of_references, &name);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_STREQ(name, "MyType");
+
+  return_code = caosdb_entity_delete_datatype(&atomic);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_datatype(&reference);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_datatype(&list_of_atomics);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_datatype(&list_of_references);
+  EXPECT_EQ(return_code, 0);
+}
+
+TEST_F(test_ccaosdb, test_value) {
+
+  caosdb_entity_value string_value;
+  int return_code(caosdb_entity_create_string_value(&string_value, "value"));
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_entity_value int_value;
+  return_code = caosdb_entity_create_int_value(&int_value, 27);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_entity_value bool_value;
+  return_code = caosdb_entity_create_bool_value(&bool_value, true);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_entity_value double_value;
+  return_code = caosdb_entity_create_double_value(&double_value, 2.7);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_entity_value string_vector_value;
+  const char *string_values[] = {"a", "b", "c"}; // NOLINT
+  return_code = caosdb_entity_create_string_vector_value(&string_vector_value, string_values, 3);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_entity_value int_vector_value;
+  const int64_t int_values[] = {1, 2, 3}; // NOLINT
+  return_code = caosdb_entity_create_int_vector_value(&int_vector_value, int_values, 3);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_entity_value double_vector_value;
+  const double double_values[] = {1.1, 2.2, 3.3}; // NOLINT
+  return_code = caosdb_entity_create_double_vector_value(&double_vector_value, double_values, 3);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_entity_value bool_vector_value;
+  const bool bool_values[] = {true, false, false}; // NOLINT
+  return_code = caosdb_entity_create_bool_vector_value(&bool_vector_value, bool_values, 3);
+  EXPECT_EQ(return_code, 0);
+
+  // One thorough check, afterwards only the ones that should be true
+  bool is_a(false);
+  return_code = caosdb_entity_value_is_null(&string_value, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_value_is_string(&string_value, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_TRUE(is_a);
+  return_code = caosdb_entity_value_is_double(&string_value, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_value_is_integer(&string_value, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_value_is_bool(&string_value, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_value_is_vector(&string_value, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+
+  caosdb_entity_value_is_integer(&int_value, &is_a);
+  EXPECT_TRUE(is_a);
+
+  caosdb_entity_value_is_bool(&bool_value, &is_a);
+  EXPECT_TRUE(is_a);
+
+  caosdb_entity_value_is_double(&double_value, &is_a);
+  EXPECT_TRUE(is_a);
+
+  caosdb_entity_value_is_vector(&string_vector_value, &is_a);
+  EXPECT_TRUE(is_a);
+
+  caosdb_entity_value_is_vector(&int_vector_value, &is_a);
+  EXPECT_TRUE(is_a);
+
+  caosdb_entity_value_is_vector(&double_vector_value, &is_a);
+  EXPECT_TRUE(is_a);
+
+  caosdb_entity_value_is_vector(&bool_vector_value, &is_a);
+  EXPECT_TRUE(is_a);
+
+  char *out_string = nullptr; // NOLINT
+  return_code = caosdb_entity_value_get_as_string(&string_value, &out_string);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_STREQ(out_string, "value");
+
+  int64_t out_int(0);
+  return_code = caosdb_entity_value_get_as_integer(&int_value, &out_int);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_EQ(out_int, 27);
+
+  bool out_bool(false);
+  return_code = caosdb_entity_value_get_as_bool(&bool_value, &out_bool);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_TRUE(out_bool);
+
+  double out_double(0);
+  return_code = caosdb_entity_value_get_as_double(&double_value, &out_double);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_EQ(out_double, 2.7);
+
+  int list_length(0);
+  return_code = caosdb_entity_value_get_as_vector_size(&string_vector_value, &list_length);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_EQ(list_length, 3);
+  return_code = caosdb_entity_value_get_as_vector_size(&int_vector_value, &list_length);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_EQ(list_length, 3);
+  return_code = caosdb_entity_value_get_as_vector_size(&double_vector_value, &list_length);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_EQ(list_length, 3);
+  return_code = caosdb_entity_value_get_as_vector_size(&bool_vector_value, &list_length);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_EQ(list_length, 3);
+
+  // Only check for one, rest should be covered by this + scalar values
+  caosdb_entity_value out_val;
+  return_code = caosdb_entity_value_get_as_vector_at(&string_vector_value, &out_val, 0);
+  EXPECT_EQ(return_code, 0);
+  caosdb_entity_value_get_as_string(&out_val, &out_string);
+  EXPECT_STREQ(out_string, "a");
+  return_code = caosdb_entity_value_get_as_vector_at(&string_vector_value, &out_val, 1);
+  EXPECT_EQ(return_code, 0);
+  caosdb_entity_value_get_as_string(&out_val, &out_string);
+  EXPECT_STREQ(out_string, "b");
+  return_code = caosdb_entity_value_get_as_vector_at(&string_vector_value, &out_val, 2);
+  EXPECT_EQ(return_code, 0);
+  caosdb_entity_value_get_as_string(&out_val, &out_string);
+  EXPECT_STREQ(out_string, "c");
+
+  return_code = caosdb_entity_delete_value(&string_value);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_value(&int_value);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_value(&bool_value);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_value(&double_value);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_value(&string_vector_value);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_value(&int_vector_value);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_value(&double_vector_value);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_value(&bool_vector_value);
+  EXPECT_EQ(return_code, 0);
+}
+
 TEST_F(test_ccaosdb, test_entity) {
   caosdb_entity_entity entity;
 
@@ -174,32 +423,94 @@ TEST_F(test_ccaosdb, test_entity) {
   caosdb_entity_entity_get_description(&entity, &out);
   EXPECT_EQ(strcmp(out, "The length of an object"), 0);
 
-  caosdb_entity_entity_set_datatype(&entity, "DOUBLE", false, false);
-  bool is_list[] = {false}; // NOLINT
-  bool is_ref[] = {false};  // NOLINT
-  caosdb_entity_entity_get_datatype(&entity, &out, is_ref, is_list);
-  EXPECT_EQ(strcmp(out, "DOUBLE"), 0);
-  EXPECT_FALSE(*is_list);
-  EXPECT_FALSE(*is_ref);
+  caosdb_entity_datatype in_type;
+  caosdb_entity_create_atomic_datatype(&in_type, "DOUBLE");
+  caosdb_entity_entity_set_datatype(&entity, &in_type);
+
+  // verify that this doesn't work ...
+  return_code = caosdb_entity_entity_get_datatype(&entity, &in_type);
+  EXPECT_EQ(return_code, caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR);
+  caosdb_entity_datatype out_type;
+  // ... but does with a clean property
+  return_code = caosdb_entity_entity_get_datatype(&entity, &out_type);
+  EXPECT_EQ(return_code, 0);
+  bool is_a(false);
+  return_code = caosdb_entity_datatype_is_atomic(&out_type, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_TRUE(is_a);
+  return_code = caosdb_entity_datatype_is_reference(&out_type, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_list_of_atomic(&out_type, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_list_of_reference(&out_type, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+
+  caosdb_entity_datatype_get_datatype_name(&out_type, &out);
+  EXPECT_STREQ(out, "DOUBLE");
+
+  caosdb_entity_value in_value;
+  return_code = caosdb_entity_create_double_value(&in_value, 5.0);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_entity_set_value(&entity, &in_value);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_entity_value out_value;
+  return_code = caosdb_entity_entity_get_value(&entity, &out_value);
+  EXPECT_EQ(return_code, 0);
+
+  caosdb_entity_value_is_double(&out_value, &is_a);
+  EXPECT_TRUE(is_a);
+  caosdb_entity_value_is_null(&out_value, &is_a);
+  EXPECT_FALSE(is_a);
+  caosdb_entity_value_is_string(&out_value, &is_a);
+  EXPECT_FALSE(is_a);
+  caosdb_entity_value_is_bool(&out_value, &is_a);
+  EXPECT_FALSE(is_a);
+  caosdb_entity_value_is_integer(&out_value, &is_a);
+  EXPECT_FALSE(is_a);
+  caosdb_entity_value_is_vector(&out_value, &is_a);
+  EXPECT_FALSE(is_a);
 
-  caosdb_entity_entity_set_datatype(&entity, "Person", true, true);
-  caosdb_entity_entity_get_datatype(&entity, &out, is_ref, is_list);
-  EXPECT_EQ(strcmp(out, "Person"), 0);
-  EXPECT_TRUE(*is_list);
-  EXPECT_TRUE(*is_ref);
+  double out_double(0);
+  caosdb_entity_value_get_as_double(&out_value, &out_double);
+  EXPECT_EQ(out_double, 5.0);
+
+  // clear to re-use
+  return_code = caosdb_entity_delete_datatype(&in_type);
+  EXPECT_EQ(return_code, 0);
+  caosdb_entity_create_reference_list_datatype(&in_type, "Person");
+  caosdb_entity_entity_set_datatype(&entity, &in_type);
+
+  // works without clearing since datatype is managed by the owning entity
+  caosdb_entity_entity_get_datatype(&entity, &out_type);
+  return_code = caosdb_entity_datatype_is_atomic(&out_type, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_reference(&out_type, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_list_of_atomic(&out_type, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_FALSE(is_a);
+  return_code = caosdb_entity_datatype_is_list_of_reference(&out_type, &is_a);
+  EXPECT_EQ(return_code, 0);
+  EXPECT_TRUE(is_a);
+
+  caosdb_entity_datatype_get_datatype_name(&out_type, &out);
+  EXPECT_STREQ(out, "Person");
 
   caosdb_entity_entity_set_unit(&entity, "m");
   caosdb_entity_entity_get_unit(&entity, &out);
   EXPECT_EQ(strcmp(out, "m"), 0);
 
-  return_code = caosdb_entity_entity_set_double_value(&entity, 5.0);
+  return_code = caosdb_entity_delete_entity(&entity);
   EXPECT_EQ(return_code, 0);
-  double value[] = {0.0}; // NOLINT
-  return_code = caosdb_entity_entity_get_double_value(&entity, value);
+  return_code = caosdb_entity_delete_datatype(&in_type);
   EXPECT_EQ(return_code, 0);
-  EXPECT_EQ(*value, 5.0);
-
-  return_code = caosdb_entity_delete_entity(&entity);
+  return_code = caosdb_entity_delete_value(&in_value);
   EXPECT_EQ(return_code, 0);
 }
 
@@ -232,10 +543,14 @@ TEST_F(test_ccaosdb, test_property) {
   caosdb_entity_property_set_id(&property, "some_id");
   caosdb_entity_property_set_name(&property, "some_name");
 
-  caosdb_entity_property_set_datatype(&property, "TEXT", false, false);
+  caosdb_entity_datatype in_type;
+  caosdb_entity_create_atomic_datatype(&in_type, "TEXT");
+  caosdb_entity_property_set_datatype(&property, &in_type);
   caosdb_entity_property_set_importance(&property, "FIX");
   caosdb_entity_property_set_unit(&property, "some_unit");
-  caosdb_entity_property_set_string_value(&property, "some_value");
+  caosdb_entity_value in_value;
+  caosdb_entity_create_string_value(&in_value, "some_value");
+  caosdb_entity_property_set_value(&property, &in_value);
 
   char *out = nullptr; // NOLINT
   caosdb_entity_property_get_id(&property, &out);
@@ -244,12 +559,22 @@ TEST_F(test_ccaosdb, test_property) {
   caosdb_entity_property_get_name(&property, &out);
   EXPECT_EQ(strcmp(out, "some_name"), 0);
 
-  bool is_ref[] = {false};  // NOLINT
-  bool is_list[] = {false}; // NOLINT
-  caosdb_entity_property_get_datatype(&property, &out, is_ref, is_list);
-  EXPECT_EQ(strcmp(out, "TEXT"), 0);
-  EXPECT_FALSE(*is_ref);
-  EXPECT_FALSE(*is_list);
+  caosdb_entity_datatype out_type;
+  return_code = caosdb_entity_property_get_datatype(&property, &out_type);
+  EXPECT_EQ(return_code, 0);
+  bool is_a(false);
+
+  caosdb_entity_datatype_is_atomic(&out_type, &is_a);
+  EXPECT_TRUE(is_a);
+  caosdb_entity_datatype_is_reference(&out_type, &is_a);
+  EXPECT_FALSE(is_a);
+  caosdb_entity_datatype_is_list_of_atomic(&out_type, &is_a);
+  EXPECT_FALSE(is_a);
+  caosdb_entity_datatype_is_list_of_reference(&out_type, &is_a);
+  EXPECT_FALSE(is_a);
+
+  caosdb_entity_datatype_get_datatype_name(&out_type, &out);
+  EXPECT_STREQ(out, "TEXT");
 
   caosdb_entity_property_get_importance(&property, &out);
   EXPECT_EQ(strcmp(out, "FIX"), 0);
@@ -257,11 +582,20 @@ TEST_F(test_ccaosdb, test_property) {
   caosdb_entity_property_get_unit(&property, &out);
   EXPECT_EQ(strcmp(out, "some_unit"), 0);
 
-  caosdb_entity_property_get_string_value(&property, &out);
-  EXPECT_EQ(strcmp(out, "some_value"), 0);
+  caosdb_entity_value out_value;
+  return_code = caosdb_entity_property_get_value(&property, &out_value);
+  EXPECT_EQ(return_code, 0);
+  caosdb_entity_value_is_string(&out_value, &is_a);
+  EXPECT_TRUE(is_a);
+  caosdb_entity_value_get_as_string(&out_value, &out);
+  EXPECT_STREQ(out, "some_value");
 
   return_code = caosdb_entity_delete_property(&property);
   EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_datatype(&in_type);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_value(&in_value);
+  EXPECT_EQ(return_code, 0);
 }
 
 TEST_F(test_ccaosdb, test_string_list_property) {
@@ -270,35 +604,59 @@ TEST_F(test_ccaosdb, test_string_list_property) {
   int return_code(caosdb_entity_create_property(&property));
   EXPECT_EQ(return_code, 0);
 
-  return_code = caosdb_entity_property_set_datatype(&property, "TEXT", false, true);
+  caosdb_entity_datatype in_type;
+  return_code = caosdb_entity_create_atomic_list_datatype(&in_type, "TEXT");
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_property_set_datatype(&property, &in_type);
   EXPECT_EQ(return_code, 0);
 
+  caosdb_entity_value in_value;
   const char *value_list[] = {"val0", "val1", "val2"}; // NOLINT
-  return_code = caosdb_entity_property_set_string_list_value(&property, value_list, 3);
+  return_code = caosdb_entity_create_string_vector_value(&in_value, value_list, 3);
   EXPECT_EQ(return_code, 0);
-
-  char *out = nullptr;      // NOLINT
-  bool is_ref[] = {false};  // NOLINT
-  bool is_list[] = {false}; // NOLINT
-  return_code = caosdb_entity_property_get_datatype(&property, &out, is_ref, is_list);
+  return_code = caosdb_entity_property_set_value(&property, &in_value);
   EXPECT_EQ(return_code, 0);
-  EXPECT_EQ(strcmp(out, "TEXT"), 0);
-  EXPECT_FALSE(*is_ref);
-  EXPECT_TRUE(*is_list);
 
-  int length = -1; // NOLINT
-  return_code = caosdb_entity_property_get_value_list_length(&property, &length);
+  caosdb_entity_datatype out_type;
+  return_code = caosdb_entity_property_get_datatype(&property, &out_type);
   EXPECT_EQ(return_code, 0);
+
+  bool is_a(false);
+  caosdb_entity_datatype_is_atomic(&out_type, &is_a);
+  EXPECT_FALSE(is_a);
+  caosdb_entity_datatype_is_reference(&out_type, &is_a);
+  EXPECT_FALSE(is_a);
+  caosdb_entity_datatype_is_list_of_atomic(&out_type, &is_a);
+  EXPECT_TRUE(is_a);
+  caosdb_entity_datatype_is_list_of_reference(&out_type, &is_a);
+  EXPECT_FALSE(is_a);
+  char *out = nullptr; // NOLINT
+  caosdb_entity_datatype_get_datatype_name(&out_type, &out);
+  EXPECT_STREQ(out, "TEXT");
+
+  caosdb_entity_value out_value;
+  caosdb_entity_property_get_value(&property, &out_value);
+  caosdb_entity_value_is_vector(&out_value, &is_a);
+  EXPECT_TRUE(is_a);
+  int length(-1);
+  caosdb_entity_value_get_as_vector_size(&out_value, &length);
   EXPECT_EQ(length, 3);
 
+  caosdb_entity_value list_elt;
   for (int i = 0; i < length; i++) {
-    return_code = caosdb_entity_property_get_string_list_value_at(&property, &out, i);
+    return_code = caosdb_entity_value_get_as_vector_at(&out_value, &list_elt, i);
+    EXPECT_EQ(return_code, 0);
+    return_code = caosdb_entity_value_get_as_string(&list_elt, &out);
     EXPECT_EQ(return_code, 0);
-    EXPECT_EQ(strcmp(value_list[i], out), 0); // NOLINT
+    EXPECT_STREQ(value_list[i], out); // NOLINT
   }
 
   return_code = caosdb_entity_delete_property(&property);
   EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_datatype(&in_type);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_value(&in_value);
+  EXPECT_EQ(return_code, 0);
 }
 
 TEST_F(test_ccaosdb, test_int_list_property) {
@@ -307,36 +665,58 @@ TEST_F(test_ccaosdb, test_int_list_property) {
   int return_code(caosdb_entity_create_property(&property));
   EXPECT_EQ(return_code, 0);
 
-  return_code = caosdb_entity_property_set_datatype(&property, "INTEGER", false, true);
+  caosdb_entity_datatype in_type;
+  caosdb_entity_create_atomic_list_datatype(&in_type, "INTEGER");
+  return_code = caosdb_entity_property_set_datatype(&property, &in_type);
   EXPECT_EQ(return_code, 0);
 
   const int64_t value_list[] = {1, 2, 3}; // NOLINT
-  return_code = caosdb_entity_property_set_int_list_value(&property, &(value_list)[0], 3);
+  caosdb_entity_value in_value;
+  caosdb_entity_create_int_vector_value(&in_value, value_list, 3);
+  return_code = caosdb_entity_property_set_value(&property, &in_value);
   EXPECT_EQ(return_code, 0);
 
-  char *dt_out = nullptr;   // NOLINT
-  bool is_ref[] = {false};  // NOLINT
-  bool is_list[] = {false}; // NOLINT
-  return_code = caosdb_entity_property_get_datatype(&property, &dt_out, is_ref, is_list);
+  caosdb_entity_datatype out_type;
+  return_code = caosdb_entity_property_get_datatype(&property, &out_type);
   EXPECT_EQ(return_code, 0);
-  EXPECT_STREQ(dt_out, "INTEGER");
-  EXPECT_FALSE(*is_ref);
-  EXPECT_TRUE(*is_list);
 
-  int length = -1; // NOLINT
-  return_code = caosdb_entity_property_get_value_list_length(&property, &length);
-  EXPECT_EQ(return_code, 0);
+  bool is_a(false);
+  caosdb_entity_datatype_is_atomic(&out_type, &is_a);
+  EXPECT_FALSE(is_a);
+  caosdb_entity_datatype_is_reference(&out_type, &is_a);
+  EXPECT_FALSE(is_a);
+  caosdb_entity_datatype_is_list_of_atomic(&out_type, &is_a);
+  EXPECT_TRUE(is_a);
+  caosdb_entity_datatype_is_list_of_reference(&out_type, &is_a);
+  EXPECT_FALSE(is_a);
+  char *out = nullptr; // NOLINT
+  caosdb_entity_datatype_get_datatype_name(&out_type, &out);
+  EXPECT_STREQ(out, "INTEGER");
+
+  caosdb_entity_value out_value;
+  caosdb_entity_property_get_value(&property, &out_value);
+  caosdb_entity_value_is_vector(&out_value, &is_a);
+  EXPECT_TRUE(is_a);
+  int length(-1);
+  caosdb_entity_value_get_as_vector_size(&out_value, &length);
   EXPECT_EQ(length, 3);
 
+  int64_t out_int = -1;
+  caosdb_entity_value list_elt;
   for (int i = 0; i < length; i++) {
-    int64_t out = -1;
-    return_code = caosdb_entity_property_get_int_list_value_at(&property, &out, i);
+    return_code = caosdb_entity_value_get_as_vector_at(&out_value, &list_elt, i);
+    EXPECT_EQ(return_code, 0);
+    return_code = caosdb_entity_value_get_as_integer(&list_elt, &out_int);
     EXPECT_EQ(return_code, 0);
-    EXPECT_EQ(value_list[i], out); // NOLINT
+    EXPECT_EQ(value_list[i], out_int); // NOLINT
   }
 
   return_code = caosdb_entity_delete_property(&property);
   EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_datatype(&in_type);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_value(&in_value);
+  EXPECT_EQ(return_code, 0);
 }
 
 TEST_F(test_ccaosdb, test_bool_list_property) {
@@ -345,36 +725,58 @@ TEST_F(test_ccaosdb, test_bool_list_property) {
   int return_code(caosdb_entity_create_property(&property));
   EXPECT_EQ(return_code, 0);
 
-  return_code = caosdb_entity_property_set_datatype(&property, "BOOLEAN", false, true);
+  caosdb_entity_datatype in_type;
+  caosdb_entity_create_atomic_list_datatype(&in_type, "BOOLEAN");
+  return_code = caosdb_entity_property_set_datatype(&property, &in_type);
   EXPECT_EQ(return_code, 0);
 
   const bool value_list[] = {true, true, false}; // NOLINT
-  return_code = caosdb_entity_property_set_boolean_list_value(&property, &(value_list)[0], 3);
+  caosdb_entity_value in_value;
+  caosdb_entity_create_bool_vector_value(&in_value, value_list, 3);
+  return_code = caosdb_entity_property_set_value(&property, &in_value);
   EXPECT_EQ(return_code, 0);
 
-  char *dt_out = nullptr;   // NOLINT
-  bool is_ref[] = {false};  // NOLINT
-  bool is_list[] = {false}; // NOLINT
-  return_code = caosdb_entity_property_get_datatype(&property, &dt_out, is_ref, is_list);
+  caosdb_entity_datatype out_type;
+  return_code = caosdb_entity_property_get_datatype(&property, &out_type);
   EXPECT_EQ(return_code, 0);
-  EXPECT_STREQ(dt_out, "BOOLEAN");
-  EXPECT_FALSE(*is_ref);
-  EXPECT_TRUE(*is_list);
 
-  int length = -1; // NOLINT
-  return_code = caosdb_entity_property_get_value_list_length(&property, &length);
-  EXPECT_EQ(return_code, 0);
+  bool is_a(false);
+  caosdb_entity_datatype_is_atomic(&out_type, &is_a);
+  EXPECT_FALSE(is_a);
+  caosdb_entity_datatype_is_reference(&out_type, &is_a);
+  EXPECT_FALSE(is_a);
+  caosdb_entity_datatype_is_list_of_atomic(&out_type, &is_a);
+  EXPECT_TRUE(is_a);
+  caosdb_entity_datatype_is_list_of_reference(&out_type, &is_a);
+  EXPECT_FALSE(is_a);
+  char *out = nullptr; // NOLINT
+  caosdb_entity_datatype_get_datatype_name(&out_type, &out);
+  EXPECT_STREQ(out, "BOOLEAN");
+
+  caosdb_entity_value out_value;
+  caosdb_entity_property_get_value(&property, &out_value);
+  caosdb_entity_value_is_vector(&out_value, &is_a);
+  EXPECT_TRUE(is_a);
+  int length(-1);
+  caosdb_entity_value_get_as_vector_size(&out_value, &length);
   EXPECT_EQ(length, 3);
 
+  bool out_bool(false);
+  caosdb_entity_value list_elt;
   for (int i = 0; i < length; i++) {
-    bool out = true;
-    return_code = caosdb_entity_property_get_boolean_list_value_at(&property, &out, i);
+    return_code = caosdb_entity_value_get_as_vector_at(&out_value, &list_elt, i);
+    EXPECT_EQ(return_code, 0);
+    return_code = caosdb_entity_value_get_as_bool(&list_elt, &out_bool);
     EXPECT_EQ(return_code, 0);
-    EXPECT_EQ(value_list[i], out); // NOLINT
+    EXPECT_EQ(value_list[i], out_bool); // NOLINT
   }
 
   return_code = caosdb_entity_delete_property(&property);
   EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_datatype(&in_type);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_value(&in_value);
+  EXPECT_EQ(return_code, 0);
 }
 
 TEST_F(test_ccaosdb, test_entity_with_parent_and_property) {
@@ -392,8 +794,12 @@ TEST_F(test_ccaosdb, test_entity_with_parent_and_property) {
   caosdb_entity_property_set_id(&input_property, "property_id");
   caosdb_entity_property_set_name(&input_property, "property_name");
 
-  caosdb_entity_property_set_datatype(&input_property, "TEXT", false, false);
-  caosdb_entity_property_set_string_value(&input_property, "property_value");
+  caosdb_entity_datatype in_type;
+  caosdb_entity_create_atomic_datatype(&in_type, "TEXT");
+  caosdb_entity_value in_value;
+  caosdb_entity_create_string_value(&in_value, "property_value");
+  caosdb_entity_property_set_datatype(&input_property, &in_type);
+  caosdb_entity_property_set_value(&input_property, &in_value);
 
   caosdb_entity_entity entity;
   return_code = caosdb_entity_create_entity(&entity);
@@ -432,19 +838,37 @@ TEST_F(test_ccaosdb, test_entity_with_parent_and_property) {
   caosdb_entity_property_get_name(&output_property, &out);
   EXPECT_EQ(strcmp(in, out), 0);
 
-  bool is_list[] = {false}; // NOLINT
-  bool is_ref[] = {false};  // NOLINT
-  caosdb_entity_property_get_datatype(&input_property, &in, is_ref, is_list);
-  EXPECT_FALSE(*is_list);
-  EXPECT_FALSE(*is_ref);
-  caosdb_entity_property_get_datatype(&output_property, &out, is_ref, is_list);
-  EXPECT_FALSE(*is_list);
-  EXPECT_FALSE(*is_ref);
-  EXPECT_EQ(strcmp(in, out), 0);
-
-  caosdb_entity_property_get_string_value(&input_property, &in);
-  caosdb_entity_property_get_string_value(&output_property, &out);
-  EXPECT_EQ(strcmp(in, out), 0);
+  caosdb_entity_datatype out_type;
+  caosdb_entity_property_get_datatype(&output_property, &out_type);
+
+  bool in_is(false);
+  bool out_is(false);
+  caosdb_entity_datatype_is_atomic(&in_type, &in_is);
+  caosdb_entity_datatype_is_atomic(&out_type, &out_is);
+  EXPECT_EQ(in_is, out_is);
+  caosdb_entity_datatype_is_reference(&in_type, &in_is);
+  caosdb_entity_datatype_is_reference(&out_type, &out_is);
+  EXPECT_EQ(in_is, out_is);
+  caosdb_entity_datatype_is_list_of_atomic(&in_type, &in_is);
+  caosdb_entity_datatype_is_list_of_atomic(&out_type, &out_is);
+  EXPECT_EQ(in_is, out_is);
+  caosdb_entity_datatype_is_list_of_reference(&in_type, &in_is);
+  caosdb_entity_datatype_is_list_of_reference(&out_type, &out_is);
+  EXPECT_EQ(in_is, out_is);
+
+  caosdb_entity_datatype_get_datatype_name(&in_type, &in);
+  caosdb_entity_datatype_get_datatype_name(&out_type, &out);
+  EXPECT_STREQ(in, out);
+
+  caosdb_entity_value out_value;
+  caosdb_entity_property_get_value(&output_property, &out_value);
+  caosdb_entity_value_is_string(&in_value, &in_is);
+  EXPECT_TRUE(in_is);
+  caosdb_entity_value_is_string(&out_value, &out_is);
+  EXPECT_TRUE(out_is);
+  caosdb_entity_value_get_as_string(&in_value, &in);
+  caosdb_entity_value_get_as_string(&out_value, &out);
+  EXPECT_STREQ(in, out);
 
   caosdb_entity_parent output_parent;
   return_code = caosdb_entity_entity_get_parent(&entity, &output_parent, 0);
@@ -465,6 +889,10 @@ TEST_F(test_ccaosdb, test_entity_with_parent_and_property) {
   EXPECT_EQ(return_code, 0);
   return_code = caosdb_entity_delete_entity(&entity);
   EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_datatype(&in_type);
+  EXPECT_EQ(return_code, 0);
+  return_code = caosdb_entity_delete_value(&in_value);
+  EXPECT_EQ(return_code, 0);
 
   // This tests the `_deletable` flag. The wrapped cpp objects of
   // `output_parent` and `output_property` are owned by the entity, so
diff --git a/test/test_data_type.cpp b/test/test_data_type.cpp
index bb2e97ba412d52a979e060f2d9920d591c07e9e8..51624a7e0513f4654f2eaa9fdf3519399726199d 100644
--- a/test/test_data_type.cpp
+++ b/test/test_data_type.cpp
@@ -53,17 +53,17 @@ TEST(test_data_type, test_atomic) {
     // the different AtomicDataType are associated with integers
     entity.SetDataType(map_el.first);
     EXPECT_TRUE(entity.GetDataType().IsAtomic());
-    EXPECT_EQ(entity.GetDataType().AsAtomic(), map_el.first);
+    EXPECT_EQ(entity.GetDataType().GetAsAtomic(), map_el.first);
 
     proto_data_type.set_atomic_data_type(static_cast<ProtoAtomicDataType>(map_el.first));
     DataType data_type(&proto_data_type);
     entity.SetDataType(data_type);
 
     EXPECT_FALSE(data_type.IsReference());
-    EXPECT_EQ(data_type.AsReference().GetName(), std::basic_string<char>(""));
+    EXPECT_EQ(data_type.GetAsReference().GetName(), std::basic_string<char>(""));
     EXPECT_FALSE(data_type.IsList());
     EXPECT_TRUE(data_type.IsAtomic());
-    EXPECT_EQ(data_type.AsAtomic(), map_el.first);
+    EXPECT_EQ(data_type.GetAsAtomic(), map_el.first);
   }
 }
 
@@ -74,7 +74,7 @@ TEST(test_data_type, test_reference) {
   entity.SetRole(Role::PROPERTY);
   entity.SetDataType("Person");
   EXPECT_TRUE(entity.GetDataType().IsReference());
-  EXPECT_EQ(entity.GetDataType().AsReference().GetName(), "Person");
+  EXPECT_EQ(entity.GetDataType().GetAsReference().GetName(), "Person");
 
   proto_data_type.mutable_reference_data_type()->set_name("Person");
   DataType data_type(&proto_data_type);
@@ -83,7 +83,7 @@ TEST(test_data_type, test_reference) {
   EXPECT_TRUE(data_type.IsReference());
   EXPECT_FALSE(data_type.IsList());
   EXPECT_FALSE(data_type.IsAtomic());
-  EXPECT_EQ(data_type.AsReference().GetName(), "Person");
+  EXPECT_EQ(data_type.GetAsReference().GetName(), "Person");
 }
 
 TEST(test_data_type, test_list_of_atomic) {
@@ -93,7 +93,7 @@ TEST(test_data_type, test_list_of_atomic) {
     EXPECT_FALSE(data_type.IsReference());
     EXPECT_FALSE(data_type.IsAtomic());
     EXPECT_TRUE(data_type.IsList());
-    const auto &list_data_type = data_type.AsList();
+    const auto &list_data_type = data_type.GetAsList();
     EXPECT_EQ(list_data_type.GetReferenceDataType().GetName(), std::basic_string<char>(""));
     EXPECT_TRUE(list_data_type.IsListOfAtomic());
     EXPECT_FALSE(list_data_type.IsListOfReference());
@@ -108,7 +108,7 @@ TEST(test_data_type, test_list_of_reference) {
   EXPECT_FALSE(data_type.IsAtomic());
   EXPECT_TRUE(data_type.IsList());
 
-  const auto &list_data_type = data_type.AsList();
+  const auto &list_data_type = data_type.GetAsList();
   EXPECT_TRUE(list_data_type.IsListOfReference());
   EXPECT_FALSE(list_data_type.IsListOfAtomic());
   const auto *wrapped = list_data_type.GetReferenceDataType().GetWrapped();
diff --git a/test/test_entity.cpp b/test/test_entity.cpp
index df196c124de8901dc047f2fdafe8efaa2e789939..75adc7e7a051cc1e2a154d6b3723e44123e28130 100644
--- a/test/test_entity.cpp
+++ b/test/test_entity.cpp
@@ -80,15 +80,15 @@ TEST(test_entity, test_property_setters) {
   EXPECT_EQ(prop.GetId(), "prop_id");
   EXPECT_EQ(prop.GetImportance(), Importance::OBLIGATORY);
   EXPECT_TRUE(prop.GetValue().IsString());
-  EXPECT_EQ(prop.GetValue().AsString(), "prop_value");
+  EXPECT_EQ(prop.GetValue().GetAsString(), "prop_value");
   EXPECT_EQ(prop.GetUnit(), "prop_unit");
   EXPECT_TRUE(prop.GetDataType().IsReference());
-  EXPECT_EQ(prop.GetDataType().AsReference().GetName(), "prop_dtype");
+  EXPECT_EQ(prop.GetDataType().GetAsReference().GetName(), "prop_dtype");
   EXPECT_FALSE(prop.GetDataType().IsList());
 
   prop.SetDataType(AtomicDataType::DATETIME);
   EXPECT_TRUE(prop.GetDataType().IsAtomic());
-  EXPECT_EQ(prop.GetDataType().AsAtomic(), AtomicDataType::DATETIME);
+  EXPECT_EQ(prop.GetDataType().GetAsAtomic(), AtomicDataType::DATETIME);
   EXPECT_FALSE(prop.GetDataType().IsList());
 }
 
@@ -97,16 +97,16 @@ TEST(test_entity, test_list_property_setters) {
 
   prop.SetDataType(AtomicDataType::DATETIME); // Set as atomic first.
   EXPECT_TRUE(prop.GetDataType().IsAtomic());
-  EXPECT_EQ(prop.GetDataType().AsAtomic(), AtomicDataType::DATETIME);
+  EXPECT_EQ(prop.GetDataType().GetAsAtomic(), AtomicDataType::DATETIME);
 
   prop.SetDataType(AtomicDataType::DOUBLE, true);
   auto const &dtype = prop.GetDataType();
   EXPECT_FALSE(dtype.IsAtomic()); // Should not be true anymore.
   EXPECT_FALSE(dtype.IsReference());
   EXPECT_TRUE(dtype.IsList());
-  EXPECT_NE(dtype.AsAtomic(), AtomicDataType::DATETIME); // Should be overwritten.
-  EXPECT_TRUE(dtype.AsList().IsListOfAtomic());
-  EXPECT_EQ(dtype.AsList().GetAtomicDataType(), AtomicDataType::DOUBLE);
+  EXPECT_NE(dtype.GetAsAtomic(), AtomicDataType::DATETIME); // Should be overwritten.
+  EXPECT_TRUE(dtype.GetAsList().IsListOfAtomic());
+  EXPECT_EQ(dtype.GetAsList().GetAtomicDataType(), AtomicDataType::DOUBLE);
 }
 
 TEST(test_entity, test_append_property) {
@@ -200,11 +200,11 @@ TEST(test_entity, test_insert_with_role) {
 
   EXPECT_EQ(entity.GetRole(), Role::PROPERTY);
   EXPECT_TRUE(entity.GetDataType().IsAtomic());
-  EXPECT_EQ(entity.GetDataType().AsAtomic(), AtomicDataType::DOUBLE);
+  EXPECT_EQ(entity.GetDataType().GetAsAtomic(), AtomicDataType::DOUBLE);
   EXPECT_EQ(entity.GetName(), "Length");
   EXPECT_EQ(entity.GetUnit(), "m");
   EXPECT_TRUE(entity.GetValue().IsDouble());
-  EXPECT_DOUBLE_EQ(entity.GetValue().AsDouble(), 5.5);
+  EXPECT_DOUBLE_EQ(entity.GetValue().GetAsDouble(), 5.5);
 }
 
 TEST(test_entity, test_insert_with_parent) {
diff --git a/test/test_list_properties.cpp b/test/test_list_properties.cpp
index 34895dfa15eabc207c2a485f4a22fcb33428a791..27d0aad53cb9eb1342e1cb87ca24d7c3b71938f0 100644
--- a/test/test_list_properties.cpp
+++ b/test/test_list_properties.cpp
@@ -52,13 +52,13 @@ TEST(test_list_property, test_list_of_text) {
   const auto &value = entity.GetProperties().at(0).GetValue();
 
   EXPECT_TRUE(data_type.IsList());
-  EXPECT_TRUE(data_type.AsList().IsListOfAtomic());
-  EXPECT_EQ(data_type.AsList().GetAtomicDataType(), AtomicDataType::TEXT);
+  EXPECT_TRUE(data_type.GetAsList().IsListOfAtomic());
+  EXPECT_EQ(data_type.GetAsList().GetAtomicDataType(), AtomicDataType::TEXT);
 
-  EXPECT_TRUE(value.IsList());
-  EXPECT_EQ(value.AsList().size(), 3);
-  EXPECT_TRUE(value.AsList().at(1).IsString());
-  EXPECT_EQ(value.AsList().at(1).AsString(), "item2");
+  EXPECT_TRUE(value.IsVector());
+  EXPECT_EQ(value.GetAsVector().size(), 3);
+  EXPECT_TRUE(value.GetAsVector().at(1).IsString());
+  EXPECT_EQ(value.GetAsVector().at(1).GetAsString(), "item2");
 }
 
 } // namespace caosdb::entity
diff --git a/test/test_protobuf.cpp b/test/test_protobuf.cpp
index 43ab6883b42f1dca1c2785103f6a274eb2b2f1bc..6f9bda0740487db475f1e34757e4a612c59061f9 100644
--- a/test/test_protobuf.cpp
+++ b/test/test_protobuf.cpp
@@ -102,10 +102,10 @@ TEST(test_protobuf, test_copy_nested) {
   EXPECT_EQ(entity_destination.data_type().reference_data_type().name(), "src_per");
 
   Entity entity(&entity_destination);
-  EXPECT_EQ(entity.GetDataType().AsReference().GetName(), "src_per");
+  EXPECT_EQ(entity.GetDataType().GetAsReference().GetName(), "src_per");
 
   const Entity &copy_entity(entity);
-  EXPECT_EQ(copy_entity.GetDataType().AsReference().GetName(), "src_per");
+  EXPECT_EQ(copy_entity.GetDataType().GetAsReference().GetName(), "src_per");
 }
 
 } // namespace caosdb
diff --git a/test/test_value.cpp b/test/test_value.cpp
index 74d30f04b621a0e118bc7591a07aab052786c790..25f8a12909e52fee4e3ed3a6b688b1871a41a32f 100644
--- a/test/test_value.cpp
+++ b/test/test_value.cpp
@@ -42,9 +42,9 @@ TEST(test_value, test_null) {
   EXPECT_TRUE(value.IsNull());
   EXPECT_FALSE(value.IsDouble());
   EXPECT_FALSE(value.IsBool());
-  EXPECT_FALSE(value.IsInteger());
+  EXPECT_FALSE(value.IsInt64());
   EXPECT_FALSE(value.IsString());
-  EXPECT_FALSE(value.IsList());
+  EXPECT_FALSE(value.IsVector());
 }
 
 TEST(test_value, test_string) {
@@ -53,18 +53,18 @@ TEST(test_value, test_string) {
   EXPECT_TRUE(value.IsString());
   EXPECT_FALSE(value.IsDouble());
   EXPECT_FALSE(value.IsBool());
-  EXPECT_FALSE(value.IsInteger());
+  EXPECT_FALSE(value.IsInt64());
 
-  EXPECT_EQ(value.AsString(), "test");
+  EXPECT_EQ(value.GetAsString(), "test");
 
   Value empty_string(std::string(""));
   EXPECT_FALSE(empty_string.IsNull());
   EXPECT_TRUE(empty_string.IsString());
   EXPECT_FALSE(empty_string.IsDouble());
   EXPECT_FALSE(empty_string.IsBool());
-  EXPECT_FALSE(empty_string.IsInteger());
+  EXPECT_FALSE(empty_string.IsInt64());
 
-  EXPECT_EQ(empty_string.AsString(), "");
+  EXPECT_EQ(empty_string.GetAsString(), "");
 
   // Test inequality
   Value string1("1");
@@ -78,18 +78,18 @@ TEST(test_value, test_double) {
   EXPECT_FALSE(value.IsString());
   EXPECT_TRUE(value.IsDouble());
   EXPECT_FALSE(value.IsBool());
-  EXPECT_FALSE(value.IsInteger());
+  EXPECT_FALSE(value.IsInt64());
 
-  EXPECT_EQ(value.AsDouble(), 2.26);
+  EXPECT_EQ(value.GetAsDouble(), 2.26);
 
   Value nan(std::sqrt(-1.0));
   EXPECT_FALSE(nan.IsNull());
   EXPECT_FALSE(nan.IsString());
   EXPECT_TRUE(nan.IsDouble());
   EXPECT_FALSE(nan.IsBool());
-  EXPECT_FALSE(nan.IsInteger());
+  EXPECT_FALSE(nan.IsInt64());
 
-  EXPECT_TRUE(std::isnan(nan.AsDouble()));
+  EXPECT_TRUE(std::isnan(nan.GetAsDouble()));
 }
 
 TEST(test_value, test_integer) {
@@ -98,9 +98,9 @@ TEST(test_value, test_integer) {
   EXPECT_FALSE(value.IsString());
   EXPECT_FALSE(value.IsDouble());
   EXPECT_FALSE(value.IsBool());
-  EXPECT_TRUE(value.IsInteger());
+  EXPECT_TRUE(value.IsInt64());
 
-  EXPECT_EQ(value.AsInteger(), 1337);
+  EXPECT_EQ(value.GetAsInt64(), 1337);
 }
 
 TEST(test_value, test_boolean) {
@@ -109,9 +109,9 @@ TEST(test_value, test_boolean) {
   EXPECT_FALSE(value.IsString());
   EXPECT_FALSE(value.IsDouble());
   EXPECT_TRUE(value.IsBool());
-  EXPECT_FALSE(value.IsInteger());
+  EXPECT_FALSE(value.IsInt64());
 
-  EXPECT_EQ(value.AsBool(), true);
+  EXPECT_EQ(value.GetAsBool(), true);
 }
 
 TEST(test_value, test_list) {
@@ -122,17 +122,56 @@ TEST(test_value, test_list) {
   Value value(ids);
 
   EXPECT_FALSE(value.IsNull());
-  EXPECT_TRUE(value.IsList());
+  EXPECT_TRUE(value.IsVector());
   EXPECT_FALSE(value.IsString());
   EXPECT_FALSE(value.IsDouble());
   EXPECT_FALSE(value.IsBool());
-  EXPECT_FALSE(value.IsInteger());
+  EXPECT_FALSE(value.IsInt64());
 
-  auto list_value = value.AsList();
+  auto list_value = value.GetAsVector();
   int counter = 0;
-  for (auto item : list_value) {
+  for (const auto &item : list_value) {
     EXPECT_EQ(item.IsString(), true);
-    EXPECT_EQ(item.AsString(), "id" + std::to_string(counter++));
+    EXPECT_EQ(item.GetAsString(), "id" + std::to_string(counter++));
   }
 }
+
+TEST(test_value, test_scalar_value_to_value) {
+  ProtoScalarValue proto_scalar_value;
+  proto_scalar_value.set_integer_value(5);
+  ScalarValue scalar_value(&proto_scalar_value);
+  Value value(scalar_value);
+
+  EXPECT_TRUE(scalar_value.IsInt64());
+  EXPECT_TRUE(value.IsInt64());
+  EXPECT_EQ(scalar_value.GetAsInt64(), value.GetAsInt64());
+}
+
+TEST(test_value, test_abstract_value) {
+  std::vector<double> vals;
+  for (double num : {0.0, 5.6, 27.5}) {
+    vals.push_back(num);
+  }
+  Value value(vals);
+  EXPECT_TRUE(value.IsVector());
+
+  AbstractValue *abstract_value = &value;
+  EXPECT_TRUE(abstract_value->IsVector());
+
+  Value value2(*abstract_value);
+  EXPECT_TRUE(value2.IsVector());
+
+  ScalarValue scalar_value = value.GetAsVector().at(2);
+  EXPECT_TRUE(scalar_value.IsDouble());
+  EXPECT_EQ(scalar_value.GetAsDouble(), 27.5);
+
+  AbstractValue *abstract_scalar_value = &scalar_value;
+  EXPECT_TRUE(abstract_scalar_value->IsDouble());
+  EXPECT_EQ(abstract_scalar_value->GetAsDouble(), 27.5);
+
+  Value scalar_value2(*abstract_scalar_value);
+  EXPECT_TRUE(scalar_value2.IsDouble());
+  EXPECT_EQ(scalar_value2.GetAsDouble(), 27.5);
+}
+
 } // namespace caosdb::entity