diff --git a/CHANGELOG.md b/CHANGELOG.md
index c0be7c0da9095f4876f5aeb2c5dcc34f287544fd..4d2da167de45ebdfa408b05bb3d0b676003b100f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,9 +16,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 * Minimal error handling
 * Queries
 * Retrieval by id(s)
+* Enums for CaosDB datatypes, importances, roles, and collections
 
 ### Changed
 
+* Structs for value and datatype are now used internally to set and get values
+  of entities and properties.
+* `get_datatype` now returns a tuple with the datatype name and the collection
+  type (or nothing in case of scalar datatypes)
+
 ### Deprecated
 
 ### Removed
diff --git a/Project.toml b/Project.toml
index c62a453e14cf635f708a9b60c85da966b1d9cddc..59d0c2fb56947680b63b3c11c5b5e479eecf8e0e 100644
--- a/Project.toml
+++ b/Project.toml
@@ -1,7 +1,7 @@
 name = "CaosDB"
 uuid = "091fdcf5-a163-4d8f-97f4-9adce40cd04e"
 authors = ["florian <f.spreckelsen@inidscale.com>"]
-version = "0.0.3"
+version = "0.0.4"
 
 [deps]
 Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
diff --git a/src/CaosDB.jl b/src/CaosDB.jl
index e15b46db7c84354f7c72d818ce83fc57dee117b6..376fa3a1299b232d2db2cb4e7fa6f1466d66a6d9 100644
--- a/src/CaosDB.jl
+++ b/src/CaosDB.jl
@@ -29,7 +29,16 @@ export evaluate_return_code,
     CaosDBException, ClientException, GenericCaosDBException, CaosDBMessage
 
 # Exports from module Constants
-export MIN_CCAOSDB_VERSION
+# ...from Constants namespace
+export COLLECTION, DATATYPE, IMPORTANCE, MIN_CCAOSDB_VERSION, ROLE
+# ...from CaosDB datatypes
+export BOOLEAN, DATETIME, DOUBLE, INTEGER, TEXT
+# ...from CaosDB collections
+export LIST
+# ...from CaosDB entity roles
+export FILE, PROPERTY, RECORD, RECORD_TYPE
+# ...from CaosDB importances
+export FIX, OBLIGATORY, RECOMMENDED, SUGGESTED
 
 # Exports from module Utility
 export get_ccaosdb_version, get_env_fallback
@@ -55,7 +64,6 @@ export get_id,
     get_datatype,
     get_unit,
     get_value,
-    get_property_list_length,
     get_version_id,
     get_property,
     get_properties,
diff --git a/src/Constants.jl b/src/Constants.jl
index b1e5db73dc4672aa719861d5cf58e5fc918d9939..67327b08b6c1bc55d171feea575b13dba2e8d2d1 100644
--- a/src/Constants.jl
+++ b/src/Constants.jl
@@ -23,12 +23,81 @@
 
 module Constants
 
-export MIN_CCAOSDB_VERSION
+# exports from this module
+export COLLECTION, DATATYPE, IMPORTANCE, MIN_CCAOSDB_VERSION, ROLE
+
+# exports from the enum submodules
+export BOOLEAN, DATETIME, DOUBLE, INTEGER, TEXT
+
+export LIST
+
+export FILE, PROPERTY, RECORD, RECORD_TYPE
+
+export FIX, OBLIGATORY, RECOMMENDED, SUGGESTED
 
 """
 The minimum version of CaosDB's cpplib and C interface that is
 supported by this version of CaosDB.jl.
 """
-const MIN_CCAOSDB_VERSION = v"0.0.16"
+const MIN_CCAOSDB_VERSION = v"0.0.17"
+
+# enums have to be encapsulated in modules to prevent namespce conflicts, see
+# https://bleepcoder.com/julia/413856244/feature-request-getproperty-on-enum-type-to-access-instances
+module DATATYPE
+
+export BOOLEAN, DATETIME, DOUBLE, INTEGER, TEXT
+
+@enum _DATATYPE begin
+    UNSPECIFIED
+    BOOLEAN
+    INTEGER
+    DOUBLE
+    DATETIME
+    TEXT
+end
+end
+
+module COLLECTION
+
+export LIST
+
+@enum _COLLECTION begin
+    LIST
+end
+end
+
+module ROLE
+
+export FILE, PROPERTY, RECORD, RECORD_TYPE
+
+@enum _ROLE begin
+    UNSPECIFIED
+    RECORD
+    RECORD_TYPE
+    PROPERTY
+    FILE
+end
+end
+
+module IMPORTANCE
+
+export FIX, OBLIGATORY, RECOMMENDED, SUGGESTED
+
+@enum _IMPORTANCE begin
+    UNSPECIFIED
+    OBLIGATORY
+    RECOMMENDED
+    SUGGESTED
+    FIX
+end
+end
+
+using .COLLECTION
+
+using .DATATYPE
+
+using .IMPORTANCE
+
+using .ROLE
 
 end
diff --git a/src/Entity.jl b/src/Entity.jl
index 9c23a8ee1794bbd5710b829b8f29d6b7124bfb3c..6a9007d0e57d8af55483abf9cf99b6d3d2fd84ee 100644
--- a/src/Entity.jl
+++ b/src/Entity.jl
@@ -39,7 +39,6 @@ export get_id,
     get_datatype,
     get_unit,
     get_value,
-    get_property_list_length,
     get_version_id,
     get_property,
     get_properties,
@@ -83,11 +82,6 @@ using CaosDB
 # especially in case of a property which I might want to specify by
 # name, add a value, append it to a Record, and then insert it and
 # might expect the server to care for the datatype.
-#
-# Also, how much do we want to support them with typos. Currently, C
-# and C++ only understand all-capital strings for datatypes,
-# importances, roles. What about user input like "record_type",
-# "RecordType", "recordtype"?
 """
 Struct containing a pointer to the wrapped cpp entity
 object. Meant for internal use; use `CaosDB.Entity.create_entity` to
@@ -195,6 +189,66 @@ mutable struct _Message
     end
 end
 
+"""
+Struct containing a pointer to the wrapped cpp DataType object. Meant for
+internal use only; use `CaosDB.Entity.create_<type>_datatype` to create a
+valid _DataType object or use the `set/get_datatype` functions.
+"""
+mutable struct _DataType
+    wrapped_datatype::Ptr{Cvoid}
+    _deletable::Bool
+
+    function _DataType(managed_by_julia::Bool = false)
+
+        datatype = new()
+        datatype._deletable = false
+
+        if managed_by_julia
+            function f(t)
+                ccall(
+                    (:caosdb_entity_delete_datatype, CaosDB.library_name),
+                    Cint,
+                    (Ref{_DataType},),
+                    Ref{_DataType}(t),
+                )
+            end
+            finalizer(f, datatype)
+        end
+
+        return datatype
+    end
+end
+
+"""
+Struct containing a pointer to the wrapped cpp AbstractValue object. Meant for
+internal use only; use `CaosDB.Entity.create_value` to create a _Value object or
+use the `set/get_value` functions`.
+"""
+mutable struct _Value
+    wrapped_value::Ptr{Cvoid}
+    _deletable::Bool
+
+    function _Value(managed_by_julia::Bool = false)
+
+        value = new()
+        value._deletable = false
+
+        if managed_by_julia
+            function f(t)
+                ccall(
+                    (:caosdb_entity_delete_value, CaosDB.library_name),
+                    Cint,
+                    (Ref{_Value},),
+                    Ref{_Value}(t),
+                )
+            end
+            finalizer(f, value)
+        end
+
+        return value
+    end
+end
+
 """
     function create_entity(name::AbstractString = "")
 
@@ -232,7 +286,7 @@ function create_recordtype(name::AbstractString = "")
 
     record_type = create_entity(name)
 
-    set_role(record_type, "RECORD_TYPE")
+    set_role(record_type, CaosDB.Constants.ROLE.RECORD_TYPE)
 
     return record_type
 
@@ -248,7 +302,7 @@ function create_record(name::AbstractString = "")
 
     record = create_entity(name)
 
-    set_role(record, "RECORD")
+    set_role(record, CaosDB.Constants.ROLE.RECORD)
 
     return record
 
@@ -257,30 +311,28 @@ end
 """
     function create_property_entity(;
         name::AbstractString = "",
-        datatype::AbstractString = "",
+        datatype::Union{AbstractString,CaosDB.Constants.DATATYPE._DATATYPE} = "",
+        collection::Union{CaosDB.Constants.COLLECTION._COLLECTION,Nothing} = nothing,
         unit::AbstractString = "",
-        is_reference::Bool = false,
-        is_list::Bool = false,
     )
 
-Return a new entity object with role Record. If `name`, `datatype`, or
-`unit` were provided, its name, datatype (including whether it is a
-reference or a list), or unit are set accordingly.
+Return a new entity object with role Record. If `name`, `datatype`, or `unit`
+were provided, its name, datatype (including whether its `collection` type), or
+unit are set accordingly.
 """
 function create_property_entity(;
     name::AbstractString = "",
-    datatype::AbstractString = "",
+    datatype::Union{AbstractString,CaosDB.Constants.DATATYPE._DATATYPE} = "",
+    collection::Union{CaosDB.Constants.COLLECTION._COLLECTION,Nothing} = nothing,
     unit::AbstractString = "",
-    is_reference::Bool = false,
-    is_list::Bool = false,
 )
 
     property = create_entity(name)
 
-    set_role(property, "PROPERTY")
+    set_role(property, CaosDB.Constants.ROLE.PROPERTY)
 
     if datatype != ""
-        set_datatype(property, datatype, is_list = is_list, is_reference = is_reference)
+        set_datatype(property, datatype, collection)
     end
 
     if unit != ""
@@ -295,16 +347,14 @@ end
         name::AbstractString = "",
         id::AbstractString = "",
         value::Union{AbstractString, Number, Bool} = "",
-        datatype::AbstractString = "",
-        is_reference::Bool = false,
-        is_list::Bool = false,
+        datatype::Union{AbstractString,CaosDB.Constants.DATATYPE._DATATYPE} = "",
+        collection::Union{CaosDB.Constants.COLLECTION._COLLECTION, Nothing} = nothing,
      )
 
-Create a property object that can be appended to another `_Entity`. If
-`name`, `id`, or `value` are given, the property's name, id, or value
-are set accordingly. The datatype and whether it is a list or a
-reference can be specified with `datatype`, `is_reference`, and
-`is_list`, respectively.
+Create a property object that can be appended to another `_Entity`. If `name`,
+`id`, or `value` are given, the property's name, id, or value are set
+accordingly. The datatype and its collection type can be specified with
+`datatype` and `collection`, respectively.
 
 !!! info
 
@@ -315,9 +365,8 @@ function create_property(;
     name::AbstractString = "",
     id::AbstractString = "",
     value::Union{AbstractString,Number,Bool} = "",
-    datatype::AbstractString = "",
-    is_reference::Bool = false,
-    is_list::Bool = false,
+    datatype::Union{AbstractString,CaosDB.Constants.DATATYPE._DATATYPE} = "",
+    collection::Union{CaosDB.Constants.COLLECTION._COLLECTION,Nothing} = nothing,
 )
     property = Ref{_Property}(_Property(true))
 
@@ -339,7 +388,7 @@ function create_property(;
     end
 
     if datatype != ""
-        set_datatype(property, datatype, is_reference = is_reference, is_list = is_list)
+        set_datatype(property, datatype, collection)
     end
 
     if value != ""
@@ -373,7 +422,7 @@ function create_file_entity(;
     end
 
     file_entity = create_entity(name)
-    set_role(file_entity, "FILE")
+    set_role(file_entity, CaosDB.Constants.ROLE.FILE)
     set_local_path(file_entity, local_path)
     set_remote_path(file_entity, remote_path)
 
@@ -415,6 +464,186 @@ function create_parent(; name::AbstractString = "", id::AbstractString = "")
     return parent
 end
 
+"""
+    function create_atomic_datatype(name::CaosDB.Constants.DATATYPE._DATATYPE)
+
+Create and return a DataType object with an atomic datatype specified by the
+`name`.
+"""
+function create_atomic_datatype(name::CaosDB.Constants.DATATYPE._DATATYPE)
+
+    datatype = Ref{_DataType}(_DataType(true))
+
+    err_code = ccall(
+        (:caosdb_entity_create_atomic_datatype, CaosDB.library_name),
+        Cint,
+        (Ref{_DataType}, Cstring),
+        datatype,
+        string(name),
+    )
+
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+
+    return datatype
+end
+
+"""
+    function create_reference_datatype(name::AbstractString)
+
+Create and return a DataType object with a reference datatype specified by
+`name`.
+"""
+function create_reference_datatype(name::AbstractString)
+
+    datatype = Ref{_DataType}(_DataType(true))
+
+    err_code = ccall(
+        (:caosdb_entity_create_reference_datatype, CaosDB.library_name),
+        Cint,
+        (Ref{_DataType}, Cstring),
+        datatype,
+        name,
+    )
+
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+
+    return datatype
+end
+
+"""
+    function create_atomic_list_datatype(name::CaosDB.Constants.DATATYPE._DATATYPE)
+
+Create and return a DataType object which is a list of atomics specified by
+`name`.
+"""
+function create_atomic_list_datatype(name::CaosDB.Constants.DATATYPE._DATATYPE)
+
+    datatype = Ref{_DataType}(_DataType(true))
+
+    err_code = ccall(
+        (:caosdb_entity_create_atomic_list_datatype, CaosDB.library_name),
+        Cint,
+        (Ref{_DataType}, Cstring),
+        datatype,
+        string(name),
+    )
+
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+
+    return datatype
+end
+
+"""
+    function create_reference_list_datatype(name::AbstractString)
+
+Create and return a DataType object which is a list of references specified by
+`name`.
+"""
+function create_reference_list_datatype(name::AbstractString)
+
+    datatype = Ref{_DataType}(_DataType(true))
+
+    err_code = ccall(
+        (:caosdb_entity_create_reference_list_datatype, CaosDB.library_name),
+        Cint,
+        (Ref{_DataType}, Cstring),
+        datatype,
+        name,
+    )
+
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+
+    return datatype
+end
+
+function create_value(
+    value::Union{AbstractString,Number,Bool,Vector{T}},
+) where {T<:Union{AbstractString,Number,Bool}}
+
+    in_type = typeof(value)
+    out = Ref{_Value}(_Value(true))
+    if in_type <: AbstractString
+        err_code = ccall(
+            (:caosdb_entity_create_string_value, CaosDB.library_name),
+            Cint,
+            (Ref{_Value}, Cstring),
+            out,
+            value,
+        )
+    elseif in_type <: Bool
+        err_code = ccall(
+            (:caosdb_entity_create_bool_value, CaosDB.library_name),
+            Cint,
+            (Ref{_Value}, Bool),
+            out,
+            value,
+        )
+    elseif in_type <: Integer
+        err_code = ccall(
+            (:caosdb_entity_create_int_value, CaosDB.library_name),
+            Cint,
+            (Ref{_Value}, Clong),
+            out,
+            Clong(value),
+        )
+    elseif in_type <: Number
+        err_code = ccall(
+            (:caosdb_entity_create_double_value, CaosDB.library_name),
+            Cint,
+            (Ref{_Value}, Cdouble),
+            out,
+            Cdouble(value),
+        )
+    elseif in_type <: Vector{T} where {T<:AbstractString}
+        err_code = ccall(
+            (:caosdb_entity_create_string_vector_value, CaosDB.library_name),
+            Cint,
+            (Ref{_Value}, Ptr{Ptr{Cchar}}, Cint),
+            out,
+            value,
+            Cint(length(value)),
+        )
+    elseif in_type <: Vector{T} where {T<:Bool}
+        err_code = ccall(
+            (:caosdb_entity_create_bool_vector_value, CaosDB.library_name),
+            Cint,
+            (Ref{_Value}, Ptr{Bool}, Cint),
+            out,
+            value,
+            Cint(length(value)),
+        )
+    elseif in_type <: Vector{T} where {T<:Integer}
+        err_code = ccall(
+            (:caosdb_entity_create_int_vector_value, CaosDB.library_name),
+            Cint,
+            (Ref{_Value}, Ptr{Clong}, Cint),
+            out,
+            Vector{Clong}(value),
+            Cint(length(value)),
+        )
+    elseif in_type <: Vector{T} where {T<:Number}
+        err_code = ccall(
+            (:caosdb_entity_create_double_vector_value, CaosDB.library_name),
+            Cint,
+            (Ref{_Value}, Ptr{Cdouble}, Cint),
+            out,
+            Vector{Cdouble}(value),
+            Cint(length(value)),
+        )
+    else
+        # Should never enter here but treat it just in case
+        throw(
+            ArgumentError(
+                "The argument of type $in_type couldn't be converted into a valid CaosDB value object.",
+            ),
+        )
+    end
+
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+
+    return out
+end
+
 """
     function get_id(entity::Ref{_Entity})
 
@@ -500,7 +729,9 @@ function get_role(entity::Ref{_Entity})
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
 
-    return unsafe_string(out[])
+    rolename = unsafe_string(out[])
+    role = getproperty(CaosDB.Constants.ROLE, Symbol(rolename))
+    return role
 end
 
 """
@@ -657,33 +888,99 @@ function get_description(message::Ref{_Message})
     return unsafe_string(out[])
 end
 
-# TODO(henrik, daniel) Is this the best way to return name, is_ref,
-# and is_list to the users? Should we split it up?
+"""
+    function _get_datatype(datatype::Ref{_DataType})
+
+Return a tuple that contains the name of the `datatype`, and its collection type
+(`nothing` in case of a scalar datatype).
+"""
+function _get_datatype(datatype::Ref{_DataType})
+
+    name = Ref{Ptr{UInt8}}(Ptr{UInt8}())
+    err_code = ccall(
+        (:caosdb_entity_datatype_get_datatype_name, CaosDB.library_name),
+        Cint,
+        (Ref{_DataType}, Ref{Ptr{UInt8}}),
+        datatype,
+        name,
+    )
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+    name = unsafe_string(name[])
+
+    is_a = Ref{Bool}(false)
+    err_code = ccall(
+        (:caosdb_entity_datatype_is_atomic, CaosDB.library_name),
+        Cint,
+        (Ref{_DataType}, Ref{Bool}),
+        datatype,
+        is_a,
+    )
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+    if is_a[]
+        return getproperty(CaosDB.Constants.DATATYPE, Symbol(name)), nothing
+    end
+
+    err_code = ccall(
+        (:caosdb_entity_datatype_is_reference, CaosDB.library_name),
+        Cint,
+        (Ref{_DataType}, Ref{Bool}),
+        datatype,
+        is_a,
+    )
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+    if is_a[]
+        return name, nothing
+    end
+
+    err_code = ccall(
+        (:caosdb_entity_datatype_is_list_of_atomic, CaosDB.library_name),
+        Cint,
+        (Ref{_DataType}, Ref{Bool}),
+        datatype,
+        is_a,
+    )
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+    if is_a[]
+        return getproperty(CaosDB.Constants.DATATYPE, Symbol(name)),
+        CaosDB.Constants.COLLECTION.LIST
+    end
+
+    err_code = ccall(
+        (:caosdb_entity_datatype_is_list_of_reference, CaosDB.library_name),
+        Cint,
+        (Ref{_DataType}, Ref{Bool}),
+        datatype,
+        is_a,
+    )
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+    if is_a[]
+        return name, CaosDB.Constants.COLLECTION.LIST
+    end
+
+    throw(CaosDB.Exceptions.ClientException("Unkown datatype"))
+
+end
+
 """
     function get_datatype(entity::Ref{_Entity})
 
-Return a tuple that contains the name of the datatype of the given
-`entity`, whether it is a reference, and whether it is a list.
+Return a tuple that contains the name of the datatype of the given `entity`, and
+its collection type (`nothing` in case of a scalar datatype).
 """
 function get_datatype(entity::Ref{_Entity})
 
-    out = Ref{Ptr{UInt8}}(Ptr{UInt8}())
-    is_ref = Ref{Bool}(false)
-    is_list = Ref{Bool}(false)
-
+    out = Ref{_DataType}(_DataType())
     err_code = ccall(
         (:caosdb_entity_entity_get_datatype, CaosDB.library_name),
         Cint,
-        (Ref{_Entity}, Ref{Ptr{UInt8}}, Ref{Bool}, Ref{Bool}),
+        (Ref{_Entity}, Ref{_DataType}),
         entity,
         out,
-        is_ref,
-        is_list,
     )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
 
-    return unsafe_string(out[]), is_ref[], is_list[]
+    return _get_datatype(out)
 end
 
 """
@@ -694,23 +991,18 @@ Return a tuple that contains the name of the datatype of the given
 """
 function get_datatype(property::Ref{_Property})
 
-    out = Ref{Ptr{UInt8}}(Ptr{UInt8}())
-    is_ref = Ref{Bool}(false)
-    is_list = Ref{Bool}(false)
-
+    out = Ref{_DataType}(_DataType())
     err_code = ccall(
         (:caosdb_entity_property_get_datatype, CaosDB.library_name),
         Cint,
-        (Ref{_Property}, Ref{Ptr{UInt8}}, Ref{Bool}, Ref{Bool}),
+        (Ref{_Property}, Ref{_DataType}),
         property,
         out,
-        is_ref,
-        is_list,
     )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
 
-    return unsafe_string(out[]), is_ref[], is_list[]
+    return _get_datatype(out)
 end
 
 """
@@ -758,428 +1050,229 @@ function get_unit(property::Ref{_Property})
 end
 
 """
-    function get_value(entity::Ref{_Entity})
-
-Return the value of the given `entity`
-"""
-function get_value(entity::Ref{_Entity})
-
-    _caosdb_dtypes = ("INTEGER", "DOUBLE", "BOOLEAN", "TEXT")
-
-    ent_datatype = get_datatype(entity)
-    is_list = ent_datatype[3]
-    if ent_datatype[1] in _caosdb_dtypes
-        if !is_list
-            if ent_datatype[1] == "INTEGER"
-                out = Ref{Clong}(0)
-                err_code = ccall(
-                    (:caosdb_entity_entity_get_int_value, CaosDB.library_name),
-                    Cint,
-                    (Ref{_Entity}, Ref{Clong}),
-                    entity,
-                    out,
-                )
-
-                out = out[]
-            elseif ent_datatype[1] == "DOUBLE"
-                out = Ref{Cdouble}(0)
-                err_code = ccall(
-                    (:caosdb_entity_entity_get_double_value, CaosDB.library_name),
-                    Cint,
-                    (Ref{_Entity}, Ref{Cdouble}),
-                    entity,
-                    out,
-                )
-                out = out[]
-            elseif ent_datatype[1] == "BOOLEAN"
-                out = Ref{Cint}(0)
-                err_code = ccall(
-                    (:caosdb_entity_entity_get_boolean_value, CaosDB.library_name),
-                    Cint,
-                    (Ref{_Entity}, Ref{Cint}),
-                    entity,
-                    out,
-                )
-                out = convert(Bool, out[])
-            elseif ent_datatype[1] == "TEXT"
-                out = Ref{Ptr{UInt8}}(Ptr{UInt8}())
-                err_code = ccall(
-                    (:caosdb_entity_entity_get_string_value, CaosDB.library_name),
-                    Cint,
-                    (Ref{_Entity}, Ref{Ptr{UInt8}}),
-                    entity,
-                    out,
-                )
-                out = unsafe_string(out[])
-            end
-        else
-            list_length = get_property_list_length(entity)
-            if ent_datatype[1] == "INTEGER"
-                out = Vector{Clong}()
-                for i::Cint = 1:list_length
-                    temp = get_int_list_value_at(entity, i)
-                    append!(out, temp)
-                end
-            elseif ent_datatype[1] == "DOUBLE"
-                out = Vector{Cdouble}()
-                for i::Cint = 1:list_length
-                    temp = get_double_list_value_at(entity, i)
-                    append!(out, temp)
-                end
-            elseif ent_datatype[1] == "BOOLEAN"
-                out = Vector{Bool}()
-                for i::Cint = 1:list_length
-                    temp = get_bool_list_value_at(entity, i)
-                    append!(out, temp)
-                end
-            elseif ent_datatype[1] == "TEXT"
-                out = Vector{String}()
-                for i::Cint = 1:list_length
-                    temp = get_string_list_value_at(entity, i)
-                    append!(out, [temp])
-                end
-            end
-        end
-    elseif ent_datatype[2]
-        # is reference
-        if !is_list
-            out = Ref{Ptr{UInt8}}(Ptr{UInt8}())
-            err_code = ccall(
-                (:caosdb_entity_entity_get_string_value, CaosDB.library_name),
-                Cint,
-                (Ref{_Entity}, Ref{Ptr{UInt8}}),
-                entity,
-                out,
-            )
-            out = unsafe_string(out[])
-        else
-            # is list of references
-            list_length = get_property_list_length(entity)
-            out = [get_string_list_value_at(entity, Cint(ii)) for ii = 1:list_length]
-        end
-    end
-
-    if @isdefined err_code
-        CaosDB.Exceptions.evaluate_return_code(err_code)
-    end
-
-    return out
-end
-
-"""
-    function get_value(property::Ref{_Property})
+    function _get_value(value::Ref{_Value})
 
-Return the value of the given `property`
+Return the value of the given CaosDB value object.
 """
-function get_value(property::Ref{_Property})
+function _get_value(value::Ref{_Value})
 
-    _caosdb_dtypes = ("INTEGER", "DOUBLE", "BOOLEAN", "TEXT")
-
-    prop_datatype = get_datatype(property)
-    is_list = prop_datatype[3]
-    if prop_datatype[1] in _caosdb_dtypes
-        if !is_list
-            if prop_datatype[1] == "INTEGER"
-                out = Ref{Clong}(0)
-                err_code = ccall(
-                    (:caosdb_entity_property_get_int_value, CaosDB.library_name),
-                    Cint,
-                    (Ref{_Property}, Ref{Clong}),
-                    property,
-                    out,
-                )
-
-                out = out[]
-            elseif prop_datatype[1] == "DOUBLE"
-                out = Ref{Cdouble}(0)
-                err_code = ccall(
-                    (:caosdb_entity_property_get_double_value, CaosDB.library_name),
-                    Cint,
-                    (Ref{_Property}, Ref{Cdouble}),
-                    property,
-                    out,
-                )
-                out = out[]
-            elseif prop_datatype[1] == "BOOLEAN"
-                out = Ref{Cint}(0)
-                err_code = ccall(
-                    (:caosdb_entity_property_get_boolean_value, CaosDB.library_name),
-                    Cint,
-                    (Ref{_Property}, Ref{Cint}),
-                    property,
-                    out,
-                )
-                out = convert(Bool, out[])
-            elseif prop_datatype[1] == "TEXT"
-                out = Ref{Ptr{UInt8}}(Ptr{UInt8}())
-                err_code = ccall(
-                    (:caosdb_entity_property_get_string_value, CaosDB.library_name),
-                    Cint,
-                    (Ref{_Property}, Ref{Ptr{UInt8}}),
-                    property,
-                    out,
-                )
-                out = unsafe_string(out[])
-            end
-        else
-            list_length = get_property_list_length(property)
-            if prop_datatype[1] == "INTEGER"
-                out = Vector{Clong}()
-                for i::Cint = 1:list_length
-                    temp = get_int_list_value_at(property, i)
-                    append!(out, temp)
-                end
-            elseif prop_datatype[1] == "DOUBLE"
-                out = Vector{Cdouble}()
-                for i::Cint = 1:list_length
-                    temp = get_double_list_value_at(property, i)
-                    append!(out, temp)
-                end
-            elseif prop_datatype[1] == "BOOLEAN"
-                out = Vector{Bool}()
-                for i::Cint = 1:list_length
-                    temp = get_bool_list_value_at(property, i)
-                    append!(out, temp)
-                end
-            elseif prop_datatype[1] == "TEXT"
-                out = Vector{String}()
-                for i::Cint = 1:list_length
-                    temp = get_string_list_value_at(property, i)
-                    append!(out, [temp])
-                end
-            end
-        end
-    elseif prop_datatype[2]
-        # is reference
-        if !is_list
-            out = Ref{Ptr{UInt8}}(Ptr{UInt8}())
-            err_code = ccall(
-                (:caosdb_entity_property_get_string_value, CaosDB.library_name),
-                Cint,
-                (Ref{_Property}, Ref{Ptr{UInt8}}),
-                property,
-                out,
-            )
-            out = unsafe_string(out[])
-        else
-            # is list of references
-            list_length = get_property_list_length(property)
-            out = [get_string_list_value_at(property, Cint(ii)) for ii = 1:list_length]
-        end
-    end
-    if @isdefined err_code
-        CaosDB.Exceptions.evaluate_return_code(err_code)
-    end
-
-    return out
-end
-
-"""
-    function get_property_list_length(property::Ref{_Property})
-
-Return the length of the list of the given `property`
-"""
-function get_property_list_length(property::Ref{_Property})
-
-    length = Ref{Cint}(0)
+    is_a = Ref{Bool}(false)
 
+    # value may be null
     err_code = ccall(
-        (:caosdb_entity_property_get_value_list_length, CaosDB.library_name),
+        (:caosdb_entity_value_is_null, CaosDB.library_name),
         Cint,
-        (Ref{_Property}, Ref{Cint}),
-        property,
-        length,
+        (Ref{_Value}, Ref{Bool}),
+        value,
+        is_a,
     )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
 
-    return length[]
-end
-
-"""
-    function get_property_list_length(entity::Ref{_Entity})
-
-Return the length of the list of the given `entity`
-"""
-function get_property_list_length(entity::Ref{_Entity})
-
-    length = Ref{Cint}(0)
-
-    err_code = ccall(
-        (:caosdb_entity_entity_get_value_list_length, CaosDB.library_name),
-        Cint,
-        (Ref{_Entity}, Ref{Cint}),
-        entity,
-        length,
-    )
-
-    CaosDB.Exceptions.evaluate_return_code(err_code)
-
-    return length[]
-end
-
-"""
-    function get_int_list_value_at(property::Ref{_Property}, index::Cint)
+    if is_a[]
+        return nothing
+    end
 
-Return the value of the INTEGER list of the given `property` at the position `index`.
-"""
-function get_int_list_value_at(property::Ref{_Property}, index::Cint)
-    out = Ref{Clong}(0)
+    # scalar string
     err_code = ccall(
-        (:caosdb_entity_property_get_int_list_value_at, CaosDB.library_name),
+        (:caosdb_entity_value_is_string, CaosDB.library_name),
         Cint,
-        (Ref{_Property}, Ref{Clong}, Cint),
-        property,
-        out,
-        index - Cint(1),
+        (Ref{_Value}, Ref{Bool}),
+        value,
+        is_a,
     )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
-    return out[]
-end
 
-"""
-    function get_int_list_value_at(entity::Ref{_Entity}, index::Cint)
+    if is_a[]
+        out = Ref{Ptr{UInt8}}(Ptr{UInt8}())
 
-Return the value of the INTEGER list of the given `entity` at the position `index`.
-"""
-function get_int_list_value_at(entity::Ref{_Entity}, index::Cint)
-    out = Ref{Clong}(0)
-    err_code = ccall(
-        (:caosdb_entity_entity_get_int_list_value_at, CaosDB.library_name),
-        Cint,
-        (Ref{_Entity}, Ref{Clong}, Cint),
-        entity,
-        out,
-        index - Cint(1),
-    )
+        ccall(
+            (:caosdb_entity_value_get_as_string, CaosDB.library_name),
+            Cint,
+            (Ref{_Value}, Ref{Ptr{UInt8}}),
+            value,
+            out,
+        )
 
-    CaosDB.Exceptions.evaluate_return_code(err_code)
-    return out[]
-end
+        CaosDB.Exceptions.evaluate_return_code(err_code)
 
-"""
-    function get_double_list_value_at(property::Ref{_Property}, index::Cint)
+        return unsafe_string(out[])
+    end
 
-Return the value of the DOUBLE list of the given `property` at the position `index`.
-"""
-function get_double_list_value_at(property::Ref{_Property}, index::Cint)
-    out = Ref{Cdouble}(0)
+    # integer
     err_code = ccall(
-        (:caosdb_entity_property_get_double_list_value_at, CaosDB.library_name),
+        (:caosdb_entity_value_is_integer, CaosDB.library_name),
         Cint,
-        (Ref{_Property}, Ref{Cdouble}, Cint),
-        property,
-        out,
-        index - Cint(1),
+        (Ref{_Value}, Ref{Bool}),
+        value,
+        is_a,
     )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
-    return out[]
-end
 
-"""
-    function get_double_list_value_at(entity::Ref{_Entity}, index::Cint)
+    if is_a[]
+        out = Ref{Clong}(0)
 
-Return the value of the DOUBLE list of the given `entity` at the position `index`.
-"""
-function get_double_list_value_at(entity::Ref{_Entity}, index::Cint)
-    out = Ref{Cdouble}(0)
+        ccall(
+            (:caosdb_entity_value_get_as_integer, CaosDB.library_name),
+            Cint,
+            (Ref{_Value}, Ref{Clong}),
+            value,
+            out,
+        )
+
+        CaosDB.Exceptions.evaluate_return_code(err_code)
+
+        return out[]
+    end
+
+    # double
     err_code = ccall(
-        (:caosdb_entity_entity_get_double_list_value_at, CaosDB.library_name),
+        (:caosdb_entity_value_is_double, CaosDB.library_name),
         Cint,
-        (Ref{_Entity}, Ref{Cdouble}, Cint),
-        entity,
-        out,
-        index - Cint(1),
+        (Ref{_Value}, Ref{Bool}),
+        value,
+        is_a,
     )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
-    return out[]
-end
 
-"""
-    function get_bool_list_value_at(property::Ref{_Property}, index::Cint)
+    if is_a[]
+        out = Ref{Cdouble}(0)
 
-Return the value of the BOOLEAN list of the given `property` at the position `index`.
-"""
-function get_bool_list_value_at(property::Ref{_Property}, index::Cint)
-    out = Ref{Cint}(0)
+        ccall(
+            (:caosdb_entity_value_get_as_double, CaosDB.library_name),
+            Cint,
+            (Ref{_Value}, Ref{Cdouble}),
+            value,
+            out,
+        )
+
+        CaosDB.Exceptions.evaluate_return_code(err_code)
+
+        return out[]
+    end
+
+    # bool
     err_code = ccall(
-        (:caosdb_entity_property_get_boolean_list_value_at, CaosDB.library_name),
+        (:caosdb_entity_value_is_bool, CaosDB.library_name),
         Cint,
-        (Ref{_Property}, Ref{Cint}, Cint),
-        property,
-        out,
-        index - Cint(1),
+        (Ref{_Value}, Ref{Bool}),
+        value,
+        is_a,
     )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
-    out = convert(Bool, out[])
-    return out
-end
 
-"""
-    function get_bool_list_value_at(entity::Ref{_Entity}, index::Cint)
+    if is_a[]
+        out = Ref{Bool}(false)
 
-Return the value of the BOOLEAN list of the given `entity` at the position `index`.
-"""
-function get_bool_list_value_at(entity::Ref{_Entity}, index::Cint)
-    out = Ref{Cint}(0)
+        ccall(
+            (:caosdb_entity_value_get_as_bool, CaosDB.library_name),
+            Cint,
+            (Ref{_Value}, Ref{Bool}),
+            value,
+            out,
+        )
+
+        CaosDB.Exceptions.evaluate_return_code(err_code)
+
+        return convert(Bool, out[])
+    end
+
+    # vector
     err_code = ccall(
-        (:caosdb_entity_entity_get_boolean_list_value_at, CaosDB.library_name),
+        (:caosdb_entity_value_is_vector, CaosDB.library_name),
         Cint,
-        (Ref{_Entity}, Ref{Cint}, Cint),
-        entity,
-        out,
-        index - Cint(1),
+        (Ref{_Value}, Ref{Bool}),
+        value,
+        is_a,
     )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
-    out = convert(Bool, out[])
-    return out
+
+    if is_a[]
+        vector_size = Ref{Cint}(0)
+
+        err_code = ccall(
+            (:caosdb_entity_value_get_as_vector_size, CaosDB.library_name),
+            Cint,
+            (Ref{_Value}, Ref{Cint}),
+            value,
+            vector_size,
+        )
+
+        CaosDB.Exceptions.evaluate_return_code(err_code)
+
+        out = []
+        value_elt = Ref{_Value}(_Value(false))
+        for ii::Cint = 1:vector_size[]
+            err_code = ccall(
+                (:caosdb_entity_value_get_as_vector_at, CaosDB.library_name),
+                Cint,
+                (Ref{_Value}, Ref{_Value}, Cint),
+                value,
+                value_elt,
+                ii - Cint(1),
+            )
+            CaosDB.Exceptions.evaluate_return_code(err_code)
+            push!(out, _get_value(value_elt))
+        end
+
+        if length(out) > 0
+            # convert to vector of type of elements s.th. it can be re-used in a
+            # `set_value` function.
+            elt_type = typeof(out[1])
+            return convert(Vector{elt_type}, out)
+        end
+
+        return out
+    end
+
+    throw(CaosDB.Exceptions.ClientException("Unkown value."))
 end
 
 """
-    function get_string_list_value_at(property::Ref{_Property}, index::Cint)
+    function get_value(entity::Ref{_Entity})
 
-Return the value of the TEXT list of the given `property` at the position `index`.
+Return the value of the given `entity`
 """
-function get_string_list_value_at(property::Ref{_Property}, index::Cint)
-    out = Ref{Ptr{UInt8}}(Ptr{UInt8}())
+function get_value(entity::Ref{_Entity})
+
+    value = Ref{_Value}(_Value())
+
     err_code = ccall(
-        (:caosdb_entity_property_get_string_list_value_at, CaosDB.library_name),
+        (:caosdb_entity_entity_get_value, CaosDB.library_name),
         Cint,
-        (Ref{_Property}, Ref{Ptr{UInt8}}, Cint),
-        property,
-        out,
-        index - Cint(1),
+        (Ref{_Entity}, Ref{_Value}),
+        entity,
+        value,
     )
-
     CaosDB.Exceptions.evaluate_return_code(err_code)
-    out = unsafe_string(out[])
-    return out
+
+    return _get_value(value)
 end
 
 """
-    function get_string_list_value_at(entity::Ref{_Entity}, index::Cint)
+    function get_value(property::Ref{_Property})
 
-Return the value of the TEXT list of the given `entity` at the position `index`.
+Return the value of the given `property`
 """
-function get_string_list_value_at(entity::Ref{_Entity}, index::Cint)
-    out = Ref{Ptr{UInt8}}(Ptr{UInt8}())
+function get_value(property::Ref{_Property})
+
+    value = Ref{_Value}(_Value())
+
     err_code = ccall(
-        (:caosdb_entity_entity_get_string_list_value_at, CaosDB.library_name),
+        (:caosdb_entity_property_get_value, CaosDB.library_name),
         Cint,
-        (Ref{_Entity}, Ref{Ptr{UInt8}}, Cint),
-        entity,
-        out,
-        index - Cint(1),
+        (Ref{_Property}, Ref{_Value}),
+        property,
+        value,
     )
-
     CaosDB.Exceptions.evaluate_return_code(err_code)
-    out = unsafe_string(out[])
-    return out
+
+    return _get_value(value)
 end
 
 """
@@ -1239,14 +1332,16 @@ function get_importance(property::Ref{_Property})
     err_code = ccall(
         (:caosdb_entity_property_get_importance, CaosDB.library_name),
         Cint,
-        (Ref{_Entity}, Ref{Ptr{UInt8}}),
+        (Ref{_Property}, Ref{Ptr{UInt8}}),
         property,
         out,
     )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
 
-    return unsafe_string(out[])
+    imp_name = unsafe_string(out[])
+    imp = getproperty(CaosDB.Constants.IMPORTANCE, Symbol(imp_name))
+    return imp
 end
 
 """
@@ -1736,17 +1831,17 @@ function set_id(property::Ref{_Property}, id::AbstractString)
 end
 
 """
-    function set_role(entity::Ref{_Entity}, role::AbstractString)
+    function set_role(entity::Ref{_Entity}, role::CaosDB.Constants.ROLE._ROLE)
 
 Set the role of the given `entity` object.
 """
-function set_role(entity::Ref{_Entity}, role::AbstractString)
+function set_role(entity::Ref{_Entity}, role::CaosDB.Constants.ROLE._ROLE)
     err_code = ccall(
         (:caosdb_entity_entity_set_role, CaosDB.library_name),
         Cint,
         (Ref{_Entity}, Cstring),
         entity,
-        role,
+        string(role),
     )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
@@ -1823,31 +1918,25 @@ function set_description(entity::Ref{_Entity}, description::AbstractString)
     CaosDB.Exceptions.evaluate_return_code(err_code)
 end
 
-# TODO(henrik, daniel) Convenience functions for lists and references,
-# too?
 """
     function set_datatype(
         entity::Ref{_Entity},
-        datatype::AbstractString;
-        is_list::Bool = false,
-        is_reference::Bool = false,
+        datatype::AbstractString,
+        collection::Union{CaosDB.Constants.COLLECTION._COLLECTION, Nothing}
     )
 
-Set the datatype of the given `entity` object to the given `datatype`
-name. Only possible if the role of the entity is "PROPERTY". Specify
-whether it is a reference or a list with the optional `is_list` and
-`is_reference` keyword arguments. If the datatype is not a reference,
-it is checked against the Atomic Datatypes known to CaosDB and an
-exception is thrown if it is not known.
+Set the datatype of the given `entity` object to a reference to the given
+`datatype` name. Only possible if the role of the entity is "PROPERTY". Specify
+whether the datatype is a list by specifying a `collection`. If none is given, a
+scalar datatype is set.
 """
 function set_datatype(
     entity::Ref{_Entity},
-    datatype::AbstractString;
-    is_list::Bool = false,
-    is_reference::Bool = false,
+    datatype::AbstractString,
+    collection::Union{CaosDB.Constants.COLLECTION._COLLECTION,Nothing} = nothing,
 )
 
-    if get_role(entity) != "PROPERTY"
+    if get_role(entity) != CaosDB.Constants.ROLE.PROPERTY
         throw(
             CaosDB.Exceptions.ClientException(
                 "Only entities with role PROPERTY can be assigned a datatype.",
@@ -1855,54 +1944,161 @@ function set_datatype(
         )
     end
 
+    if collection == nothing
+        dtype_ref = create_reference_datatype(datatype)
+    elseif collection == CaosDB.Constants.COLLECTION.LIST
+        dtype_ref = create_reference_list_datatype(datatype)
+    else
+        throw(ArgumentError("Unkown datatype: $datatype"))
+    end
+
     err_code = ccall(
         (:caosdb_entity_entity_set_datatype, CaosDB.library_name),
         Cint,
-        (Ref{_Entity}, Cstring, Bool, Bool),
+        (Ref{_Entity}, Ref{_DataType}),
         entity,
-        datatype,
-        is_reference,
-        is_list,
+        dtype_ref,
+    )
+
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+end
+
+"""
+    function set_datatype(
+        entity::Ref{_Entity},
+        datatype::CaosDB.Constants.DATATYPE._DATATYPE,
+        collection::Union{CaosDB.Constants.COLLECTION._COLLECTION, Nothing}
+    )
+
+Set the datatype of the given `entity` object to a reference to the given atomic
+`datatype`. Only possible if the role of the entity is "PROPERTY". Specify
+whether the datatype is a list by specifying a `collection`. If none is given, a
+scalar datatype is set.
+"""
+function set_datatype(
+    entity::Ref{_Entity},
+    datatype::CaosDB.Constants.DATATYPE._DATATYPE,
+    collection::Union{CaosDB.Constants.COLLECTION._COLLECTION,Nothing} = nothing,
+)
+
+    if get_role(entity) != CaosDB.Constants.ROLE.PROPERTY
+        throw(
+            CaosDB.Exceptions.ClientException(
+                "Only entities with role PROPERTY can be assigned a datatype.",
+            ),
+        )
+    end
+
+    if collection == nothing
+        dtype_ref = create_atomic_datatype(datatype)
+    elseif collection == CaosDB.Constants.COLLECTION.LIST
+        dtype_ref = create_atomic_list_datatype(datatype)
+    else
+        throw(ArgumentError("Unkown datatype: $datatype"))
+    end
+
+    err_code = ccall(
+        (:caosdb_entity_entity_set_datatype, CaosDB.library_name),
+        Cint,
+        (Ref{_Entity}, Ref{_DataType}),
+        entity,
+        dtype_ref,
     )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
 end
 
+"""
+    function set_datatype(entity::Ref{_Entity}, datatype::Tuple{Any, Any})
+
+Convenience wrapper for the `set_datatype` functions s.th. expressions like
+`set_datatype(entity_a, get_datatype(entity_b))` work.
+"""
+function set_datatype(entity::Ref{_Entity}, datatype::Tuple{Any,Any})
+    set_datatype(entity, datatype[1], datatype[2])
+end
 
 """
     function set_datatype(
         property::Ref{_Property},
-        datatype::AbstractString;
-        is_list::Bool = false,
-        is_reference::Bool = false,
+        datatype::AbstractString,
+        collection::Union{CaosDB.Constants.COLLECTION._COLLECTION, Nothing}
     )
 
-Set the datatype of the given `property` object to the given
-`datatype` name. Specify whether it is a reference or a list with the
-optional `is_list` and `is_reference` keyword arguments. If the
-datatype is not a reference, it is checked against the Atomic
-Datatypes known to CaosDB and an exception is thrown if it is not
-known.
+Set the datatype of the given `property` object to a reference to the given
+`datatype` name. Specify whether the datatype is a list by specifying a
+`collection`. If none is given, a scalar datatype is set.
 """
 function set_datatype(
     property::Ref{_Property},
-    datatype::AbstractString;
-    is_list::Bool = false,
-    is_reference::Bool = false,
+    datatype::AbstractString,
+    collection::Union{CaosDB.Constants.COLLECTION._COLLECTION,Nothing} = nothing,
 )
+    if collection == nothing
+        dtype_ref = create_reference_datatype(datatype)
+    elseif collection == CaosDB.Constants.COLLECTION.LIST
+        dtype_ref = create_reference_list_datatype(datatype)
+    else
+        throw(ArgumentError("Unkown datatype: $datatype"))
+    end
+
     err_code = ccall(
         (:caosdb_entity_property_set_datatype, CaosDB.library_name),
         Cint,
-        (Ref{_Property}, Cstring, Bool, Bool),
+        (Ref{_Property}, Ref{_DataType}),
         property,
-        datatype,
-        is_reference,
-        is_list,
+        dtype_ref,
+    )
+
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+end
+
+"""
+    function set_datatype(
+        property::Ref{_Property},
+        datatype::CaosDB.Constants.DATATYPE._DATATYPE,
+        collection::Union{CaosDB.Constants.COLLECTION._COLLECTION, Nothing}
+    )
+
+Set the datatype of the given `property` object to a reference to the given
+atomic `datatype`. Specify whether the datatype is a list by specifying a
+`collection`. If none is given, a scalar datatype is set.
+"""
+function set_datatype(
+    property::Ref{_Property},
+    datatype::CaosDB.Constants.DATATYPE._DATATYPE,
+    collection::Union{CaosDB.Constants.COLLECTION._COLLECTION,Nothing} = nothing,
+)
+
+    if collection == nothing
+        dtype_ref = create_atomic_datatype(datatype)
+    elseif collection == CaosDB.Constants.COLLECTION.LIST
+        dtype_ref = create_atomic_list_datatype(datatype)
+    else
+        throw(ArgumentError("Unkown datatype: $datatype"))
+    end
+
+    err_code = ccall(
+        (:caosdb_entity_property_set_datatype, CaosDB.library_name),
+        Cint,
+        (Ref{_Property}, Ref{_DataType}),
+        property,
+        dtype_ref,
     )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
 end
 
+"""
+    function set_datatype(property::Ref{_Property}, datatype::Tuple{Any, Any})
+
+Convenience wrapper for the `set_datatype` functions s.th. expressions like
+`set_datatype(property_a, get_datatype(property_b))` work.
+"""
+function set_datatype(property::Ref{_Property}, datatype::Tuple{Any,Any})
+    set_datatype(property, datatype[1], datatype[2])
+end
+
 """
     function set_unit(entity::Ref{_Entity}, unit::AbstractString)
 
@@ -1920,7 +2116,6 @@ function set_unit(entity::Ref{_Entity}, unit::AbstractString)
     CaosDB.Exceptions.evaluate_return_code(err_code)
 end
 
-
 """
     function set_unit(property::Ref{_Property}, unit::AbstractString)
 
@@ -1938,8 +2133,6 @@ function set_unit(property::Ref{_Property}, unit::AbstractString)
     CaosDB.Exceptions.evaluate_return_code(err_code)
 end
 
-# TODO(henrik, daniel) There is no check for the correct datatype
-# here. Should we add this?
 """
     function set_value(
         entity::Ref{_Entity},
@@ -1956,7 +2149,7 @@ function set_value(
     value::Union{AbstractString,Number,Bool,Vector{T}},
 ) where {T<:Union{AbstractString,Number,Bool}}
 
-    if get_role(entity) != "PROPERTY"
+    if get_role(entity) != CaosDB.Constants.ROLE.PROPERTY
         throw(
             CaosDB.Exceptions.ClientException(
                 "Only entites with role PROPERTY may be assigned a value.",
@@ -1964,80 +2157,15 @@ function set_value(
         )
     end
 
-    in_type = typeof(value)
-    if in_type <: AbstractString
-        err_code = ccall(
-            (:caosdb_entity_entity_set_string_value, CaosDB.library_name),
-            Cint,
-            (Ref{_Entity}, Cstring),
-            entity,
-            value,
-        )
-    elseif in_type <: Bool
-        err_code = ccall(
-            (:caosdb_entity_entity_set_boolean_value, CaosDB.library_name),
-            Cint,
-            (Ref{_Entity}, Bool),
-            entity,
-            value,
-        )
-    elseif in_type <: Integer
-        err_code = ccall(
-            (:caosdb_entity_entity_set_int_value, CaosDB.library_name),
-            Cint,
-            (Ref{_Entity}, Clong),
-            entity,
-            Clong(value),
-        )
-    elseif in_type <: Number
-        err_code = ccall(
-            (:caosdb_entity_entity_set_double_value, CaosDB.library_name),
-            Cint,
-            (Ref{_Entity}, Cdouble),
-            entity,
-            Cdouble(value),
-        )
-    else
-        # Type is a vector now
-        vec_length = Cint(length(value))
-        if in_type <: Vector{T} where {T<:AbstractString}
-            err_code = ccall(
-                (:caosdb_entity_entity_set_string_list_value, CaosDB.library_name),
-                Cint,
-                (Ref{_Entity}, Ptr{Ptr{Cchar}}, Cint),
-                entity,
-                value,
-                vec_length,
-            )
-        elseif in_type <: Vector{T} where {T<:Bool}
-            err_code = ccall(
-                (:caosdb_entity_entity_set_boolean_list_value, CaosDB.library_name),
-                Cint,
-                (Ref{_Entity}, Ptr{Bool}, Cint),
-                entity,
-                value,
-                vec_length,
-            )
-        elseif in_type <: Vector{T} where {T<:Integer}
-            err_code = ccall(
-                (:caosdb_entity_entity_set_int_list_value, CaosDB.library_name),
-                Cint,
-                (Ref{_Entity}, Ptr{Clong}, Cint),
-                entity,
-                Vector{Clong}(value),
-                vec_length,
-            )
-        elseif in_type <: Vector{T} where {T<:Number}
-            err_code = ccall(
-                (:caosdb_entity_entity_set_double_list_value, CaosDB.library_name),
-                Cint,
-                (Ref{_Entity}, Ptr{Cdouble}, Cint),
-                entity,
-                Vector{Cdouble}(value),
-                vec_length,
-            )
-        end
-    end
+    value_ref = create_value(value)
+
+    err_code = ccall(
+        (:caosdb_entity_entity_set_value, CaosDB.library_name),
+        Cint,
+        (Ref{_Entity}, Ref{_Value}),
+        entity,
+        value_ref,
+    )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
 end
@@ -2053,96 +2181,37 @@ function set_value(
     value::Union{AbstractString,Number,Bool,Vector{T}},
 ) where {T<:Union{AbstractString,Number,Bool}}
 
-    in_type = typeof(value)
-    if in_type <: AbstractString
-        err_code = ccall(
-            (:caosdb_entity_property_set_string_value, CaosDB.library_name),
-            Cint,
-            (Ref{_Property}, Cstring),
-            property,
-            value,
-        )
-    elseif in_type <: Bool
-        err_code = ccall(
-            (:caosdb_entity_property_set_boolean_value, CaosDB.library_name),
-            Cint,
-            (Ref{_Property}, Bool),
-            property,
-            value,
-        )
-    elseif in_type <: Integer
-        err_code = ccall(
-            (:caosdb_entity_property_set_int_value, CaosDB.library_name),
-            Cint,
-            (Ref{_Property}, Clong),
-            property,
-            Clong(value),
-        )
-    elseif in_type <: Number
-        err_code = ccall(
-            (:caosdb_entity_property_set_double_value, CaosDB.library_name),
-            Cint,
-            (Ref{_Property}, Cdouble),
-            property,
-            Cdouble(value),
-        )
-    else
-        # Type is a vector now
-        vec_length = Cint(length(value))
-        if in_type <: Vector{T} where {T<:AbstractString}
-            err_code = ccall(
-                (:caosdb_entity_property_set_string_list_value, CaosDB.library_name),
-                Cint,
-                (Ref{_Property}, Ptr{Ptr{Cchar}}, Cint),
-                property,
-                value,
-                vec_length,
-            )
-        elseif in_type <: Vector{T} where {T<:Bool}
-            err_code = ccall(
-                (:caosdb_entity_property_set_boolean_list_value, CaosDB.library_name),
-                Cint,
-                (Ref{_Property}, Ptr{Bool}, Cint),
-                property,
-                value,
-                vec_length,
-            )
-        elseif in_type <: Vector{T} where {T<:Integer}
-            err_code = ccall(
-                (:caosdb_entity_property_set_int_list_value, CaosDB.library_name),
-                Cint,
-                (Ref{_Property}, Ptr{Clong}, Cint),
-                property,
-                Vector{Clong}(value),
-                vec_length,
-            )
-        elseif in_type <: Vector{T} where {T<:Number}
-            err_code = ccall(
-                (:caosdb_entity_property_set_double_list_value, CaosDB.library_name),
-                Cint,
-                (Ref{_Property}, Ptr{Cdouble}, Cint),
-                property,
-                Vector{Cdouble}(value),
-                vec_length,
-            )
-        end
-    end
+    value_ref = create_value(value)
+
+    err_code = ccall(
+        (:caosdb_entity_property_set_value, CaosDB.library_name),
+        Cint,
+        (Ref{_Property}, Ref{_Value}),
+        property,
+        value_ref,
+    )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
 end
 
 """
-    function set_importance(property::Ref{_Property}, importance::AbstractString)
+    function set_importance(
+        property::Ref{_Property},
+        importance::CaosDB.Constants.IMPORTANCE._IMPORTANCE
+    )
 
 Set the importance of the given `property` object.
 """
-function set_importance(property::Ref{_Property}, importance::AbstractString)
+function set_importance(
+    property::Ref{_Property},
+    importance::CaosDB.Constants.IMPORTANCE._IMPORTANCE,
+)
     err_code = ccall(
         (:caosdb_entity_property_set_importance, CaosDB.library_name),
         Cint,
         (Ref{_Property}, Cstring),
         property,
-        importance,
+        string(importance),
     )
 
     CaosDB.Exceptions.evaluate_return_code(err_code)
diff --git a/test/runtests.jl b/test/runtests.jl
index c2ae2face7fdc82805eab16055069ae4a33c5b04..e0d445d9d08367a7f9978ec02a0a9225bed6ea44 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -102,12 +102,13 @@ using CaosDB
 
         rt_with_name = CaosDB.Entity.create_recordtype("TestRT")
         @test CaosDB.Entity.get_name(rt_with_name) == "TestRT"
-        @test CaosDB.Entity.get_role(rt_with_name) == "RECORD_TYPE"
+        @test CaosDB.Entity.get_role(rt_with_name) == CaosDB.Constants.ROLE.RECORD_TYPE
 
         prop_with_name_and_unit =
             CaosDB.Entity.create_property_entity(name = "TestProp", unit = "m")
         @test CaosDB.Entity.get_name(prop_with_name_and_unit) == "TestProp"
-        @test CaosDB.Entity.get_role(prop_with_name_and_unit) == "PROPERTY"
+        @test CaosDB.Entity.get_role(prop_with_name_and_unit) ==
+              CaosDB.Constants.ROLE.PROPERTY
         @test CaosDB.Entity.get_unit(prop_with_name_and_unit) == "m"
 
         rec_with_parent_and_props = CaosDB.Entity.create_record("TestRec")
@@ -119,7 +120,7 @@ using CaosDB
         # cannot set the datatype of a record
         @test_throws CaosDB.Exceptions.ClientException CaosDB.Entity.set_datatype(
             rec_with_parent_and_props,
-            "INTEGER",
+            CaosDB.Constants.DATATYPE.INTEGER,
         )
 
         par1 = CaosDB.Entity.create_parent(name = "Parent1")
@@ -145,22 +146,20 @@ using CaosDB
 
         prop1 = CaosDB.Entity.create_property(name = "Property1", value = "2")
         prop2 = CaosDB.Entity.create_property(id = "id_of_property_2")
-        CaosDB.Entity.set_datatype(prop2, "TEXT")
+        CaosDB.Entity.set_datatype(prop2, CaosDB.Constants.DATATYPE.TEXT)
         prop3 = CaosDB.Entity.create_property(name = "Property3")
         CaosDB.Entity.append_properties(rec_with_parent_and_props, [prop1, prop2, prop3])
         @test length(CaosDB.Entity.get_properties(rec_with_parent_and_props)) == 3
-        # properties can be accessed as a list
 
-        # TODO(florian) Fix this once we have a reasonable treatment of value objects in Extern C.
-        @test_broken CaosDB.Entity.get_value(
+        # properties can be accessed as a list
+        @test CaosDB.Entity.get_value(
             CaosDB.Entity.get_properties(rec_with_parent_and_props)[1],
         ) == "2"
-        type, is_ref, is_list = CaosDB.Entity.get_datatype(
+        type, collection = CaosDB.Entity.get_datatype(
             CaosDB.Entity.get_properties(rec_with_parent_and_props)[2],
         )
-        @test type == "TEXT"
-        @test is_ref == false
-        @test is_list == false
+        @test type == CaosDB.Constants.DATATYPE.TEXT
+        @test collection == nothing
         @test CaosDB.Entity.get_id(
             CaosDB.Entity.get_properties(rec_with_parent_and_props)[2],
         ) == "id_of_property_2"
@@ -177,7 +176,7 @@ using CaosDB
             local_path = string(pwd(), "/", "caosdbfilefortests.txt"),
             remote_path = "/remote_path/file.txt",
         )
-        @test CaosDB.Entity.get_role(file_ent) == "FILE"
+        @test CaosDB.Entity.get_role(file_ent) == CaosDB.Constants.ROLE.FILE
         @test CaosDB.Entity.get_name(file_ent) == "TestFile"
         # local file not found
         rm(string(pwd(), "/", "caosdbfilefortests.txt"))
@@ -191,21 +190,16 @@ using CaosDB
     @testset "Property values and datatypes" begin
         @testset "Entity properties" begin
             int_prop =
-                CaosDB.Entity.create_property_entity(name = "IntProp", datatype = "INTEGER")
-            double_prop = CaosDB.Entity.create_property_entity(
-                name = "DoubleProp",
-                datatype = "DOUBLE",
-            )
-            bool_prop = CaosDB.Entity.create_property_entity(
-                name = "BoolProp",
-                datatype = "BOOLEAN",
-            )
+                CaosDB.Entity.create_property_entity(name = "IntProp", datatype = INTEGER)
+            double_prop =
+                CaosDB.Entity.create_property_entity(name = "DoubleProp", datatype = DOUBLE)
+            bool_prop =
+                CaosDB.Entity.create_property_entity(name = "BoolProp", datatype = BOOLEAN)
             string_prop =
-                CaosDB.Entity.create_property_entity(name = "StringProp", datatype = "TEXT")
+                CaosDB.Entity.create_property_entity(name = "StringProp", datatype = TEXT)
             ref_prop = CaosDB.Entity.create_property_entity(
                 name = "RefProp",
                 datatype = "MyRefType",
-                is_reference = true,
             )
             CaosDB.Entity.set_value(int_prop, 123)
             CaosDB.Entity.set_value(double_prop, 10.246)
@@ -222,38 +216,37 @@ using CaosDB
             @test isa(CaosDB.Entity.get_value(bool_prop), Bool)
             @test isa(CaosDB.Entity.get_value(string_prop), String)
             @test isa(CaosDB.Entity.get_value(ref_prop), String)
-            @test CaosDB.Entity.get_datatype(int_prop) == ("INTEGER", false, false)
-            @test CaosDB.Entity.get_datatype(double_prop) == ("DOUBLE", false, false)
-            @test CaosDB.Entity.get_datatype(bool_prop) == ("BOOLEAN", false, false)
-            @test CaosDB.Entity.get_datatype(string_prop) == ("TEXT", false, false)
-            @test CaosDB.Entity.get_datatype(ref_prop) == ("MyRefType", true, false)
+            @test CaosDB.Entity.get_datatype(int_prop) == (INTEGER, nothing)
+            @test CaosDB.Entity.get_datatype(double_prop) == (DOUBLE, nothing)
+            @test CaosDB.Entity.get_datatype(bool_prop) == (BOOLEAN, nothing)
+            @test CaosDB.Entity.get_datatype(string_prop) == (TEXT, nothing)
+            @test CaosDB.Entity.get_datatype(ref_prop) == ("MyRefType", nothing)
 
             """ Test lists """
             int_list_prop = CaosDB.Entity.create_property_entity(
                 name = "IntProp",
-                datatype = "INTEGER",
-                is_list = true,
+                datatype = INTEGER,
+                collection = LIST,
             )
             double_list_prop = CaosDB.Entity.create_property_entity(
                 name = "DoubleProp",
-                datatype = "DOUBLE",
-                is_list = true,
+                datatype = DOUBLE,
+                collection = LIST,
             )
             bool_list_prop = CaosDB.Entity.create_property_entity(
                 name = "BoolProp",
-                datatype = "BOOLEAN",
-                is_list = true,
+                datatype = BOOLEAN,
+                collection = LIST,
             )
             string_list_prop = CaosDB.Entity.create_property_entity(
                 name = "StringProp",
-                datatype = "TEXT",
-                is_list = true,
+                datatype = TEXT,
+                collection = LIST,
             )
             ref_list_prop = CaosDB.Entity.create_property_entity(
                 name = "RefListProp",
                 datatype = "MyRefType",
-                is_list = true,
-                is_reference = true,
+                collection = LIST,
             )
             CaosDB.Entity.set_value(int_list_prop, [123, 456])
             CaosDB.Entity.set_value(double_list_prop, [10.246, 3.14])
@@ -270,25 +263,41 @@ using CaosDB
             @test isa(CaosDB.Entity.get_value(bool_list_prop), Vector{Bool})
             @test isa(CaosDB.Entity.get_value(string_list_prop), Vector{String})
             @test isa(CaosDB.Entity.get_value(ref_list_prop), Vector{String})
-            @test CaosDB.Entity.get_datatype(int_list_prop) == ("INTEGER", false, true)
-            @test CaosDB.Entity.get_datatype(double_list_prop) == ("DOUBLE", false, true)
-            @test CaosDB.Entity.get_datatype(bool_list_prop) == ("BOOLEAN", false, true)
-            @test CaosDB.Entity.get_datatype(string_list_prop) == ("TEXT", false, true)
-            @test CaosDB.Entity.get_datatype(ref_list_prop) == ("MyRefType", true, true)
+            @test CaosDB.Entity.get_datatype(int_list_prop) == (INTEGER, LIST)
+            @test CaosDB.Entity.get_datatype(double_list_prop) == (DOUBLE, LIST)
+            @test CaosDB.Entity.get_datatype(bool_list_prop) == (BOOLEAN, LIST)
+            @test CaosDB.Entity.get_datatype(string_list_prop) == (TEXT, LIST)
+            @test CaosDB.Entity.get_datatype(ref_list_prop) == ("MyRefType", LIST)
+
+            # Check copying of values and datatypes
+            copied_prop = CaosDB.Entity.create_property_entity(name = "CopiedProp")
+            set_datatype(copied_prop, get_datatype(int_list_prop))
+            set_value(copied_prop, get_value(int_list_prop))
+            @test get_datatype(copied_prop) == get_datatype(int_list_prop)
+            @test get_value(copied_prop) == get_value(int_list_prop)
+            set_datatype(copied_prop, get_datatype(double_prop))
+            set_value(copied_prop, get_value(double_prop))
+            @test get_datatype(copied_prop) == get_datatype(double_prop)
+            @test get_value(copied_prop) == get_value(double_prop)
+            set_datatype(copied_prop, get_datatype(ref_list_prop))
+            set_value(copied_prop, get_value(ref_list_prop))
+            @test get_datatype(copied_prop) == get_datatype(ref_list_prop)
+            # TODO(fspreck) Re-try once
+            # https://gitlab.indiscale.com/caosdb/src/caosdb-cpplib/-/issues/24
+            # has been fixed.
+            @test_broken get_value(copied_prop) == get_value(ref_list_prop)
+
         end
+
         @testset "Property properties" begin
-            int_prop = CaosDB.Entity.create_property(name = "IntProp", datatype = "INTEGER")
+            int_prop = CaosDB.Entity.create_property(name = "IntProp", datatype = INTEGER)
             double_prop =
-                CaosDB.Entity.create_property(name = "DoubleProp", datatype = "DOUBLE")
-            bool_prop =
-                CaosDB.Entity.create_property(name = "BoolProp", datatype = "BOOLEAN")
+                CaosDB.Entity.create_property(name = "DoubleProp", datatype = DOUBLE)
+            bool_prop = CaosDB.Entity.create_property(name = "BoolProp", datatype = BOOLEAN)
             string_prop =
-                CaosDB.Entity.create_property(name = "StringProp", datatype = "TEXT")
-            ref_prop = CaosDB.Entity.create_property(
-                name = "RefProp",
-                datatype = "MyRefType",
-                is_reference = true,
-            )
+                CaosDB.Entity.create_property(name = "StringProp", datatype = TEXT)
+            ref_prop =
+                CaosDB.Entity.create_property(name = "RefProp", datatype = "MyRefType")
             CaosDB.Entity.set_value(int_prop, 123)
             CaosDB.Entity.set_value(double_prop, 10.246)
             CaosDB.Entity.set_value(bool_prop, true)
@@ -304,38 +313,37 @@ using CaosDB
             @test isa(CaosDB.Entity.get_value(bool_prop), Bool)
             @test isa(CaosDB.Entity.get_value(string_prop), String)
             @test isa(CaosDB.Entity.get_value(ref_prop), String)
-            @test CaosDB.Entity.get_datatype(int_prop) == ("INTEGER", false, false)
-            @test CaosDB.Entity.get_datatype(double_prop) == ("DOUBLE", false, false)
-            @test CaosDB.Entity.get_datatype(bool_prop) == ("BOOLEAN", false, false)
-            @test CaosDB.Entity.get_datatype(string_prop) == ("TEXT", false, false)
-            @test CaosDB.Entity.get_datatype(ref_prop) == ("MyRefType", true, false)
+            @test CaosDB.Entity.get_datatype(int_prop) == (INTEGER, nothing)
+            @test CaosDB.Entity.get_datatype(double_prop) == (DOUBLE, nothing)
+            @test CaosDB.Entity.get_datatype(bool_prop) == (BOOLEAN, nothing)
+            @test CaosDB.Entity.get_datatype(string_prop) == (TEXT, nothing)
+            @test CaosDB.Entity.get_datatype(ref_prop) == ("MyRefType", nothing)
 
             """ Test lists """
             int_list_prop = CaosDB.Entity.create_property(
                 name = "IntProp",
-                datatype = "INTEGER",
-                is_list = true,
+                datatype = INTEGER,
+                collection = LIST,
             )
             double_list_prop = CaosDB.Entity.create_property(
                 name = "DoubleProp",
-                datatype = "DOUBLE",
-                is_list = true,
+                datatype = DOUBLE,
+                collection = LIST,
             )
             bool_list_prop = CaosDB.Entity.create_property(
                 name = "BoolProp",
-                datatype = "BOOLEAN",
-                is_list = true,
+                datatype = BOOLEAN,
+                collection = LIST,
             )
             string_list_prop = CaosDB.Entity.create_property(
                 name = "StringProp",
-                datatype = "TEXT",
-                is_list = true,
+                datatype = TEXT,
+                collection = LIST,
             )
             ref_list_prop = CaosDB.Entity.create_property(
                 name = "RefListProp",
                 datatype = "MyRefType",
-                is_list = true,
-                is_reference = true,
+                collection = LIST,
             )
             CaosDB.Entity.set_value(int_list_prop, [123, 456])
             CaosDB.Entity.set_value(double_list_prop, [10.246, 3.14])
@@ -352,11 +360,11 @@ using CaosDB
             @test isa(CaosDB.Entity.get_value(bool_list_prop), Vector{Bool})
             @test isa(CaosDB.Entity.get_value(string_list_prop), Vector{String})
             @test isa(CaosDB.Entity.get_value(ref_list_prop), Vector{String})
-            @test CaosDB.Entity.get_datatype(int_list_prop) == ("INTEGER", false, true)
-            @test CaosDB.Entity.get_datatype(double_list_prop) == ("DOUBLE", false, true)
-            @test CaosDB.Entity.get_datatype(bool_list_prop) == ("BOOLEAN", false, true)
-            @test CaosDB.Entity.get_datatype(string_list_prop) == ("TEXT", false, true)
-            @test CaosDB.Entity.get_datatype(ref_list_prop) == ("MyRefType", true, true)
+            @test CaosDB.Entity.get_datatype(int_list_prop) == (INTEGER, LIST)
+            @test CaosDB.Entity.get_datatype(double_list_prop) == (DOUBLE, LIST)
+            @test CaosDB.Entity.get_datatype(bool_list_prop) == (BOOLEAN, LIST)
+            @test CaosDB.Entity.get_datatype(string_list_prop) == (TEXT, LIST)
+            @test CaosDB.Entity.get_datatype(ref_list_prop) == ("MyRefType", LIST)
         end
     end
 end