diff --git a/include/caosdb/entity.h b/include/caosdb/entity.h
index e731f9a0d31f8a8e792ad614ea86e16d260b1b0d..99f38591fe6426c6a6b6ca1aad26d6bce5fa1aa4 100644
--- a/include/caosdb/entity.h
+++ b/include/caosdb/entity.h
@@ -2,6 +2,7 @@
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021 Florian Spreckelsen <f.spreckelsen@indiscale.com>
  * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
@@ -36,6 +37,7 @@
 namespace caosdb::entity {
 using caosdb::entity::v1alpha1::IdResponse;
 using ProtoParent = caosdb::entity::v1alpha1::Parent;
+using ProtoProperty = caosdb::entity::v1alpha1::Property;
 using ProtoEntity = caosdb::entity::v1alpha1::Entity;
 
 /**
@@ -54,8 +56,10 @@ public:
   }
 
   friend class Entity;
-  friend class Parent;
-  friend class Property;
+  // TODO(fspreck) Re-enable once we have decided how messages are
+  // appended to parents and properties
+  // friend class Parent;
+  // friend class Property;
   friend class Messages;
 
 private:
@@ -76,8 +80,9 @@ public:
   }
 
   friend class Entity;
-  friend class Parent;
-  friend class Property;
+  // TODO(fspreck) Same here.
+  // friend class Parent;
+  // friend class Property;
 
 private:
   inline Messages() : wrapped(nullptr){};
@@ -134,32 +139,32 @@ public:
     return out;
   }
 
-  // TODO(fspreck) These need implementations. See Entity::GetErrors for
-  // inspiration.
-  /**
-   * Return the error messages of this parent.
-   */
-  [[nodiscard]] inline auto GetErrors() const -> const Messages & {
-    return errors;
-  }
-  [[nodiscard]] inline auto HasErrors() const -> bool {
-    return this->errors.wrapped->size() > 0;
-  }
-  /**
-   * Return the warning messages of this parent.
-   */
-  [[nodiscard]] inline auto GetWarnings() const -> const Messages & {
-    return warnings;
-  }
-  [[nodiscard]] inline auto HasWarnings() const -> bool {
-    return this->warnings.wrapped->size() > 0;
-  }
-  /**
-   * Return the info messages of this parent.
-   */
-  [[nodiscard]] inline auto GetInfos() const -> const Messages & {
-    return infos;
-  }
+  // TODO(fspreck) Finish the following implementations once we have
+  // decided how to attach messages to parents.
+  // /**
+  //  * Return the error messages of this parent.
+  //  */
+  // [[nodiscard]] inline auto GetErrors() const -> const Messages & {
+  //   return errors;
+  // }
+  // [[nodiscard]] inline auto HasErrors() const -> bool {
+  //   return this->errors.wrapped->size() > 0;
+  // }
+  // /**
+  //  * Return the warning messages of this parent.
+  //  */
+  // [[nodiscard]] inline auto GetWarnings() const -> const Messages & {
+  //   return warnings;
+  // }
+  // [[nodiscard]] inline auto HasWarnings() const -> bool {
+  //   return this->warnings.wrapped->size() > 0;
+  // }
+  // /**
+  //  * Return the info messages of this parent.
+  //  */
+  // [[nodiscard]] inline auto GetInfos() const -> const Messages & {
+  //   return infos;
+  // }
 
   friend class Entity;
   friend class Parents;
@@ -181,9 +186,9 @@ private:
    * Message which serves as storage backend.
    */
   mutable caosdb::entity::v1alpha1::Parent *wrapped;
-  Messages errors;
-  Messages warnings;
-  Messages infos;
+  // Messages errors;
+  // Messages warnings;
+  // Messages infos;
 };
 
 /**
@@ -239,31 +244,88 @@ class Property {
 public:
   explicit inline Property(caosdb::entity::v1alpha1::Property *wrapped)
     : wrapped(wrapped){};
+  Property();
 
-  // TODO(fspreck) All of these methods need implementations.
+  /**
+   * Return the id of this  property
+   */
   [[nodiscard]] auto GetId() const -> const std::string &;
+  /**
+   * Return the name of this  property
+   */
   [[nodiscard]] auto GetName() const -> const std::string &;
+  /**
+   * Return the description of this  property
+   */
   [[nodiscard]] auto GetDescription() const -> const std::string &;
+  /**
+   * Return the importance of this  property
+   */
   [[nodiscard]] auto GetImportance() const -> const std::string &;
+  /**
+   * Return the value of this  property
+   */
   [[nodiscard]] auto GetValue() const -> const std::string &;
+  /**
+   * Return the unit of this  property
+   */
   [[nodiscard]] auto GetUnit() const -> const std::string &;
+  /**
+   * Return the datatype of this  property
+   */
   [[nodiscard]] auto GetDatatype() const -> const std::string &;
-  [[nodiscard]] auto GetErrors() const -> const Messages &;
-  [[nodiscard]] auto GetWarnings() const -> const Messages &;
-  [[nodiscard]] auto GetInfos() const -> const Messages &;
+  // TODO(fspreck) Implement these when we have decided how to attach
+  // messages to properties.
+  // [[nodiscard]] auto GetErrors() const -> const Messages &;
+  // [[nodiscard]] auto GetWarnings() const -> const Messages &;
+  // [[nodiscard]] auto GetInfos() const -> const Messages &;
 
+  /**
+   * Set the id of this property.
+   */
   auto SetId(const std::string &id) -> void;
+  /**
+   * Set the name of this property.
+   */
   auto SetName(const std::string &name) -> void;
+  /**
+   * Set the importance of this property.
+   */
   auto SetImportance(const std::string &importance) -> void;
+  /**
+   * Set the value of this property.
+   */
   auto SetValue(const std::string &value) -> void;
+  /**
+   * Set the unit of this property.
+   */
   auto SetUnit(const std::string &unit) -> void;
+  /**
+   * Set the datatype of this property.
+   */
   auto SetDatatype(const std::string &datatype) -> void;
 
+  /**
+   * Return a json string representing this property.
+   *
+   * This is intended for debugging
+   */
+  inline auto ToString() const -> const std::string {
+    google::protobuf::util::JsonOptions options;
+    std::string out;
+    google::protobuf::util::MessageToJsonString(*(this->wrapped), &out,
+                                                options);
+
+    return out;
+  }
+
   friend class Entity;
   friend class Properties;
 
 private:
-  caosdb::entity::v1alpha1::Property *wrapped;
+  static auto CreateProtoProperty() -> ProtoProperty *;
+
+  mutable caosdb::entity::v1alpha1::Property *wrapped;
 };
 
 /**
@@ -273,10 +335,18 @@ private:
  */
 class Properties {
 public:
-  // TODO(fspreck) Implementations needed (basically everything). See Parents
-  // container for inspiration.
-  [[nodiscard]] auto At(int index) const -> const Property &;
-  auto Append(const Property &property) -> void;
+  /**
+   * Return the current size of the properties container.
+   *
+   * This is also the number of properties the owningn entity currently has.
+   */
+  [[nodiscard]] inline auto Size() const -> int { return wrapped->size(); }
+  /**
+   * Return the property at the given index.
+   */
+  [[nodiscard]] auto At(int index) const -> const Property {
+    return Property(&(wrapped->at(index)));
+  }
 
   friend class Entity;
 
@@ -287,6 +357,13 @@ private:
       *wrapped)
     : wrapped(wrapped){};
 
+  /**
+   * Append a property
+   *
+   * This increases the Size() by one.
+   */
+  auto Append(const Property &property) -> void;
+
   ::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Property>
     *wrapped;
 };
@@ -366,11 +443,14 @@ public:
   auto SetUnit(const std::string &unit) -> void;
   // Currently no references or lists.
   auto SetDatatype(const std::string &datatype) -> void;
-  // TODO(fspreck) this one is tricky. See AppendParent
   auto AppendProperty(const Property &property) -> void;
 
   auto AppendParent(const Parent &parent) -> void;
   auto Switch(ProtoEntity *entity) -> void;
+  /**
+   * Copy all of this entity's features to the target ProtoEntity.
+   */
+  auto CopyTo(ProtoEntity *target) -> void;
 
 private:
   static auto CreateProtoEntity() -> ProtoEntity *;
diff --git a/src/caosdb/entity.cpp b/src/caosdb/entity.cpp
index 84105eda6bebbead819d66ae92f5b693fc293481..999ba3753b068909dc7dd54518ca5ff8bd8033bf 100644
--- a/src/caosdb/entity.cpp
+++ b/src/caosdb/entity.cpp
@@ -1,6 +1,8 @@
 /*
  * This file is a part of the CaosDB Project.
+ *
  * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021 Florian Spreckelsen <f.spreckelsen@indiscale.com>
  * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
@@ -25,13 +27,16 @@
 namespace caosdb::entity {
 using caosdb::entity::v1alpha1::IdResponse;
 using ProtoParent = caosdb::entity::v1alpha1::Parent;
+using ProtoProperty = caosdb::entity::v1alpha1::Property;
 using ProtoEntity = caosdb::entity::v1alpha1::Entity;
 using caosdb::utility::get_arena;
 
 Parent::Parent() : wrapped(Parent::CreateProtoParent()) {
-  errors.wrapped = this->wrapped->mutable_errors();
-  warnings.wrapped = this->wrapped->mutable_warnings();
-  infos.wrapped = this->wrapped->mutable_infos();
+  // TODO(fspreck) Re-enable once we have decided how to attach
+  // messages to parents.
+  // errors.wrapped = this->wrapped->mutable_errors();
+  // warnings.wrapped = this->wrapped->mutable_warnings();
+  // infos.wrapped = this->wrapped->mutable_infos();
 }
 
 auto Parent::CreateProtoParent() -> ProtoParent * {
@@ -63,6 +68,73 @@ auto Parents::Append(const Parent &parent) -> void {
   parent.wrapped = destination;
 }
 
+Property::Property() : wrapped(Property::CreateProtoProperty()) {}
+
+auto Property::CreateProtoProperty() -> ProtoProperty * {
+  return google::protobuf::Arena::CreateMessage<ProtoProperty>(get_arena());
+}
+
+[[nodiscard]] auto Property::GetId() const -> const std::string & {
+  return this->wrapped->id();
+}
+
+[[nodiscard]] auto Property::GetName() const -> const std::string & {
+  return this->wrapped->name();
+}
+
+[[nodiscard]] auto Property::GetDescription() const -> const std::string & {
+  return this->wrapped->description();
+}
+
+[[nodiscard]] auto Property::GetImportance() const -> const std::string & {
+  return this->wrapped->importance();
+}
+
+[[nodiscard]] auto Property::GetValue() const -> const std::string & {
+  return this->wrapped->value();
+}
+
+[[nodiscard]] auto Property::GetUnit() const -> const std::string & {
+  return this->wrapped->unit();
+}
+
+[[nodiscard]] auto Property::GetDatatype() const -> const std::string & {
+  return this->wrapped->datatype();
+}
+
+auto Property::SetId(const std::string &id) -> void {
+  this->wrapped->set_id(id);
+}
+
+auto Property::SetName(const std::string &name) -> void {
+  this->wrapped->set_name(name);
+}
+
+auto Property::SetImportance(const std::string &importance) -> void {
+  this->wrapped->set_importance(importance);
+}
+
+auto Property::SetValue(const std::string &value) -> void {
+  this->wrapped->set_value(value);
+}
+
+auto Property::SetUnit(const std::string &unit) -> void {
+  this->wrapped->set_unit(unit);
+}
+
+auto Property::SetDatatype(const std::string &datatype) -> void {
+  this->wrapped->set_datatype(datatype);
+}
+
+auto Properties::Append(const Property &property) -> void {
+  auto *destination = this->wrapped->Add();
+  destination->Swap(property.wrapped);
+
+  property.wrapped->Clear();
+
+  property.wrapped = destination;
+}
+
 [[nodiscard]] auto Entity::GetParents() const -> const Parents & {
   return parents;
 }
@@ -71,6 +143,14 @@ auto Entity::AppendParent(const Parent &parent) -> void {
   this->parents.Append(parent);
 }
 
+[[nodiscard]] auto Entity::GetProperties() const -> const Properties & {
+  return properties;
+}
+
+auto Entity::AppendProperty(const Property &property) -> void {
+  this->properties.Append(property);
+}
+
 auto Entity::CreateProtoEntity() -> ProtoEntity * {
   return google::protobuf::Arena::CreateMessage<ProtoEntity>(get_arena());
 }
@@ -97,12 +177,17 @@ auto Entity::SetVersionId(const std::string &id) -> void {
   this->wrapped->mutable_version()->set_id(id);
 }
 
+// TODO(tf) Re-implement s.th. properties and parents are kept.
 auto Entity::Switch(ProtoEntity *entity) -> void {
   this->wrapped->Swap(entity);
   this->wrapped->Clear();
   this->wrapped = entity;
 }
 
+auto Entity::CopyTo(ProtoEntity *target) -> void {
+  target->CopyFrom(*(this->wrapped));
+}
+
 auto Entity::SetRole(const std::string &role) -> void {
   this->wrapped->set_role(role);
 }
diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp
index 72b59e81cf51f86d2f7cb8fe3f482753af590da5..b9482232c63e55c6fb545d4b9e2ffa35ae7c13aa 100644
--- a/src/caosdb/transaction.cpp
+++ b/src/caosdb/transaction.cpp
@@ -137,8 +137,8 @@ auto Transaction::InsertEntity(Entity *entity) noexcept -> StatusCode {
   auto *sub_request = this->request->add_requests();
   auto *proto_entity = sub_request->mutable_insert_request();
 
-  entity->Switch(proto_entity);
-
+  // copy the original entity for the transaction
+  entity->CopyTo(proto_entity);
   return StatusCode::INITIAL;
 }
 
diff --git a/test/test_entity.cpp b/test/test_entity.cpp
index 66423eb49300422439a75ec20f35e63d703053c1..ec117968e3a8d72304eacd27663889cf1cd156f0 100644
--- a/test/test_entity.cpp
+++ b/test/test_entity.cpp
@@ -3,6 +3,7 @@
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021 Florian Spreckelsen <f.spreckelsen@indiscale.com>
  * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
@@ -23,7 +24,9 @@
 #include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransactionSe...
 #include "caosdb/entity/v1alpha1/main.pb.h"      // for IdResponse, Message
 #include "caosdb/message_code.h"                 // for MessageCode
+#include "caosdb/protobuf_helper.h"              // for get_arena
 #include "caosdb/transaction.h"                  // for Transaction
+#include "google/protobuf/arena.h"               // for Arena
 #include "gtest/gtest-message.h"                 // for Message
 #include "gtest/gtest-test-part.h"               // for TestPartResult, Sui...
 #include "gtest/gtest_pred_impl.h"               // for Test, EXPECT_EQ
@@ -33,6 +36,8 @@
 
 namespace caosdb::entity {
 using caosdb::entity::v1alpha1::IdResponse;
+using ProtoEntity = caosdb::entity::v1alpha1::Entity;
+using caosdb::utility::get_arena;
 
 TEST(test_entity, test_parent_setters) {
   auto parent = Parent();
@@ -56,6 +61,79 @@ TEST(test_entity, test_append_parent) {
   EXPECT_EQ(same_parent.GetId(), "some-id");
 }
 
+TEST(test_entity, test_property_setters) {
+  auto prop = Property();
+  prop.SetName("prop_name");
+  prop.SetId("prop_id");
+  prop.SetImportance("prop_importance");
+  prop.SetValue("prop_value");
+  prop.SetUnit("prop_unit");
+  prop.SetDatatype("prop_dtype");
+
+  EXPECT_EQ(prop.GetName(), "prop_name");
+  EXPECT_EQ(prop.GetId(), "prop_id");
+  EXPECT_EQ(prop.GetImportance(), "prop_importance");
+  EXPECT_EQ(prop.GetValue(), "prop_value");
+  EXPECT_EQ(prop.GetUnit(), "prop_unit");
+  EXPECT_EQ(prop.GetDatatype(), "prop_dtype");
+}
+
+// TODO(fspreck) cognitive complexity > 25 (threshold)
+TEST(test_entity, test_append_property) { // NOLINT
+  auto entity = Entity();
+
+  auto prop = Property();
+  prop.SetName("prop_name");
+  prop.SetId("prop_id");
+  prop.SetImportance("prop_importance");
+  prop.SetValue("prop_value");
+  prop.SetUnit("prop_unit");
+  prop.SetDatatype("prop_dtype");
+
+  EXPECT_EQ(entity.GetProperties().Size(), 0);
+  entity.AppendProperty(prop);
+  EXPECT_EQ(entity.GetProperties().Size(), 1);
+
+  auto same_prop = entity.GetProperties().At(0);
+
+  EXPECT_EQ(prop.GetName(), same_prop.GetName());
+  EXPECT_EQ(prop.GetId(), same_prop.GetId());
+  EXPECT_EQ(prop.GetImportance(), same_prop.GetImportance());
+  EXPECT_EQ(prop.GetValue(), same_prop.GetValue());
+  EXPECT_EQ(prop.GetUnit(), same_prop.GetUnit());
+  EXPECT_EQ(prop.GetDatatype(), same_prop.GetDatatype());
+}
+
+TEST(test_entity, test_copy_to) {
+  auto entity = Entity();
+  entity.SetId("original_id");
+  entity.SetName("orignial_name");
+
+  auto parent = Parent();
+  parent.SetId("parent_id");
+  parent.SetName("parent_name");
+  entity.AppendParent(parent);
+
+  auto prop = Property();
+  prop.SetId("prop_id");
+  prop.SetName("prop_name");
+  entity.AppendProperty(prop);
+
+  // create protobuf entity to which all fields ae copied and then a
+  // CaoosDB entity from that protobuf entity.
+  auto *proto_copy =
+    google::protobuf::Arena::CreateMessage<ProtoEntity>(get_arena());
+  entity.CopyTo(proto_copy);
+  auto copied = Entity(proto_copy);
+
+  EXPECT_EQ(entity.GetId(), copied.GetId());
+  EXPECT_EQ(entity.GetName(), copied.GetName());
+  EXPECT_EQ(copied.GetParents().At(0).GetId(), parent.GetId());
+  EXPECT_EQ(copied.GetParents().At(0).GetName(), parent.GetName());
+  EXPECT_EQ(copied.GetProperties().At(0).GetId(), prop.GetId());
+  EXPECT_EQ(copied.GetProperties().At(0).GetName(), prop.GetName());
+}
+
 TEST(test_entity, test_insert_entity) {
   auto transaction = caosdb::transaction::Transaction(
     std::shared_ptr<transaction::EntityTransactionService::Stub>(nullptr));
@@ -98,6 +176,63 @@ TEST(test_entity, test_insert_with_role) { // NOLINT
   EXPECT_EQ(entity.GetValue(), "5.5");
 }
 
+TEST(test_entity, test_insert_with_parent) {
+  auto transaction = caosdb::transaction::Transaction(
+    std::shared_ptr<transaction::EntityTransactionService::Stub>(nullptr));
+
+  auto entity = Entity();
+  entity.SetId("entity_id");
+
+  auto parent = Parent();
+  parent.SetId("parent_id");
+  parent.SetName("parent_name");
+  EXPECT_EQ(parent.GetId(), "parent_id");
+  EXPECT_EQ(parent.GetName(), "parent_name");
+
+  entity.AppendParent(parent);
+
+  transaction.InsertEntity(&entity);
+
+  std::cout << entity.ToString() << std::endl;
+  EXPECT_EQ(entity.GetId(), "entity_id");
+  EXPECT_EQ(entity.GetParents().Size(), 1);
+  auto inserted_parent = entity.GetParents().At(0);
+  EXPECT_EQ(inserted_parent.GetId(), parent.GetId());
+  EXPECT_EQ(inserted_parent.GetName(), parent.GetName());
+}
+
+// TODO(fspreck) cognitive complexity > 25 (threshold)
+TEST(test_entity, test_insert_with_property) { // NOLINT
+  auto transaction = caosdb::transaction::Transaction(
+    std::shared_ptr<transaction::EntityTransactionService::Stub>(nullptr));
+
+  auto entity = Entity();
+  entity.SetId("entity_id");
+
+  auto prop = Property();
+  prop.SetName("prop_name");
+  prop.SetId("prop_id");
+  prop.SetImportance("prop_importance");
+  prop.SetValue("prop_value");
+  prop.SetUnit("prop_unit");
+  prop.SetDatatype("prop_dtype");
+
+  entity.AppendProperty(prop);
+
+  transaction.InsertEntity(&entity);
+
+  EXPECT_EQ(entity.GetProperties().Size(), 1);
+
+  auto inserted_prop = entity.GetProperties().At(0);
+
+  EXPECT_EQ(prop.GetName(), inserted_prop.GetName());
+  EXPECT_EQ(prop.GetId(), inserted_prop.GetId());
+  EXPECT_EQ(prop.GetImportance(), inserted_prop.GetImportance());
+  EXPECT_EQ(prop.GetValue(), inserted_prop.GetValue());
+  EXPECT_EQ(prop.GetUnit(), inserted_prop.GetUnit());
+  EXPECT_EQ(prop.GetDatatype(), inserted_prop.GetDatatype());
+}
+
 // TODO(tf) cognitive complexity > 25 (threshold)
 TEST(test_entity, test_from_id_response) { // NOLINT
   IdResponse idResponse;