diff --git a/src/storage/v3/CMakeLists.txt b/src/storage/v3/CMakeLists.txt
index f371f7b7b..b3a3d68a9 100644
--- a/src/storage/v3/CMakeLists.txt
+++ b/src/storage/v3/CMakeLists.txt
@@ -17,6 +17,7 @@ set(storage_v3_src_files
     shard_rsm.cpp
     bindings/typed_value.cpp
     expr.cpp
+    vertex.cpp
     request_helper.cpp)
 
 # ######################
diff --git a/src/storage/v3/delta.hpp b/src/storage/v3/delta.hpp
index 9548be146..1c6e57d2b 100644
--- a/src/storage/v3/delta.hpp
+++ b/src/storage/v3/delta.hpp
@@ -15,13 +15,13 @@
 #include "storage/v3/edge_ref.hpp"
 #include "storage/v3/id_types.hpp"
 #include "storage/v3/property_value.hpp"
+#include "storage/v3/vertex.hpp"
 #include "storage/v3/vertex_id.hpp"
 #include "utils/logging.hpp"
 
 namespace memgraph::storage::v3 {
 
 // Forward declarations because we only store pointers here.
-struct Vertex;
 struct Edge;
 struct Delta;
 struct CommitInfo;
diff --git a/src/storage/v3/edge.hpp b/src/storage/v3/edge.hpp
index df47b8416..c5cf6c6f7 100644
--- a/src/storage/v3/edge.hpp
+++ b/src/storage/v3/edge.hpp
@@ -21,7 +21,7 @@
 
 namespace memgraph::storage::v3 {
 
-struct Vertex;
+using EdgeContainer = std::map<Gid, Edge>;
 
 struct Edge {
   Edge(Gid gid, Delta *delta) : gid(gid), deleted(false), delta(delta) {
@@ -34,13 +34,13 @@ struct Edge {
   PropertyStore properties;
 
   bool deleted;
-  // uint8_t PAD;
+  uint8_t PAD;
   // uint16_t PAD;
 
   Delta *delta;
 };
 
-static_assert(alignof(Edge) >= 8, "The Edge should be aligned to at least 8!");
+// static_assert(alignof(Edge) >= 8, "The Edge should be aligned to at least 8!");
 
 inline bool operator==(const Edge &first, const Edge &second) { return first.gid == second.gid; }
 inline bool operator<(const Edge &first, const Edge &second) { return first.gid < second.gid; }
diff --git a/src/storage/v3/edge_accessor.hpp b/src/storage/v3/edge_accessor.hpp
index bc143c1e3..b57beeb96 100644
--- a/src/storage/v3/edge_accessor.hpp
+++ b/src/storage/v3/edge_accessor.hpp
@@ -25,7 +25,6 @@
 
 namespace memgraph::storage::v3 {
 
-struct Vertex;
 class VertexAccessor;
 struct Indices;
 
diff --git a/src/storage/v3/indices.cpp b/src/storage/v3/indices.cpp
index fc546b594..84097a26a 100644
--- a/src/storage/v3/indices.cpp
+++ b/src/storage/v3/indices.cpp
@@ -21,6 +21,7 @@
 #include "storage/v3/mvcc.hpp"
 #include "storage/v3/property_value.hpp"
 #include "storage/v3/schemas.hpp"
+#include "storage/v3/vertex.hpp"
 #include "utils/bound.hpp"
 #include "utils/logging.hpp"
 #include "utils/memory_tracker.hpp"
@@ -57,9 +58,9 @@ bool AnyVersionHasLabel(const Vertex &vertex, LabelId label, uint64_t timestamp)
   bool deleted{false};
   const Delta *delta{nullptr};
   {
-    has_label = utils::Contains(vertex.labels, label);
-    deleted = vertex.deleted;
-    delta = vertex.delta;
+    has_label = utils::Contains(vertex.second.labels, label);
+    deleted = vertex.second.deleted;
+    delta = vertex.second.delta;
   }
   if (!deleted && has_label) {
     return true;
@@ -109,10 +110,10 @@ bool AnyVersionHasLabelProperty(const Vertex &vertex, LabelId label, PropertyId
   bool deleted{false};
   const Delta *delta{nullptr};
   {
-    has_label = utils::Contains(vertex.labels, label);
-    current_value_equal_to_value = vertex.properties.IsPropertyEqual(key, value);
-    deleted = vertex.deleted;
-    delta = vertex.delta;
+    has_label = utils::Contains(vertex.second.labels, label);
+    current_value_equal_to_value = vertex.second.properties.IsPropertyEqual(key, value);
+    deleted = vertex.second.deleted;
+    delta = vertex.second.delta;
   }
 
   if (!deleted && has_label && current_value_equal_to_value) {
@@ -167,9 +168,9 @@ bool CurrentVersionHasLabel(const Vertex &vertex, LabelId label, Transaction *tr
   bool has_label{false};
   const Delta *delta{nullptr};
   {
-    deleted = vertex.deleted;
-    has_label = utils::Contains(vertex.labels, label);
-    delta = vertex.delta;
+    deleted = vertex.second.deleted;
+    has_label = utils::Contains(vertex.second.labels, label);
+    delta = vertex.second.delta;
   }
   ApplyDeltasForRead(transaction, delta, view, [&deleted, &has_label, label](const Delta &delta) {
     switch (delta.action) {
@@ -218,10 +219,10 @@ bool CurrentVersionHasLabelProperty(const Vertex &vertex, LabelId label, Propert
   bool current_value_equal_to_value = value.IsNull();
   const Delta *delta{nullptr};
   {
-    deleted = vertex.deleted;
-    has_label = utils::Contains(vertex.labels, label);
-    current_value_equal_to_value = vertex.properties.IsPropertyEqual(key, value);
-    delta = vertex.delta;
+    deleted = vertex.second.deleted;
+    has_label = utils::Contains(vertex.second.labels, label);
+    current_value_equal_to_value = vertex.second.properties.IsPropertyEqual(key, value);
+    delta = vertex.second.delta;
   }
   ApplyDeltasForRead(transaction, delta, view,
                      [&deleted, &has_label, &current_value_equal_to_value, key, label, &value](const Delta &delta) {
@@ -282,8 +283,8 @@ bool LabelIndex::CreateIndex(LabelId label, VertexContainer &vertices) {
   }
   try {
     auto acc = it->second.access();
-    for ([[maybe_unused]] auto &[pk, vertex] : vertices) {
-      if (vertex.deleted || !utils::Contains(vertex.labels, label)) {
+    for ([[maybe_unused]] auto &vertex : vertices) {
+      if (vertex.second.deleted || !VertexHasLabel(vertex, label)) {
         continue;
       }
       acc.insert(Entry{&vertex, 0});
@@ -395,7 +396,7 @@ void LabelPropertyIndex::UpdateOnAddLabel(LabelId label, Vertex *vertex, const T
     if (label_prop.first != label) {
       continue;
     }
-    auto prop_value = vertex->properties.GetProperty(label_prop.second);
+    auto prop_value = vertex->second.properties.GetProperty(label_prop.second);
     if (!prop_value.IsNull()) {
       index.emplace(prop_value, Entry{prop_value, vertex, tx.start_timestamp.logical_id});
     }
@@ -411,7 +412,7 @@ void LabelPropertyIndex::UpdateOnSetProperty(PropertyId property, const Property
     if (label_prop.second != property) {
       continue;
     }
-    if (utils::Contains(vertex->labels, label_prop.first)) {
+    if (VertexHasLabel(*vertex, label_prop.first)) {
       index.emplace(value, Entry{value, vertex, tx.start_timestamp.logical_id});
     }
   }
@@ -426,11 +427,11 @@ bool LabelPropertyIndex::CreateIndex(LabelId label, PropertyId property, VertexC
     return false;
   }
   try {
-    for ([[maybe_unused]] auto &[pk, vertex] : vertices) {
-      if (vertex.deleted || !utils::Contains(vertex.labels, label)) {
+    for ([[maybe_unused]] auto &vertex : vertices) {
+      if (vertex.second.deleted || !VertexHasLabel(vertex, label)) {
         continue;
       }
-      auto value = vertex.properties.GetProperty(property);
+      auto value = vertex.second.properties.GetProperty(property);
       if (value.IsNull()) {
         continue;
       }
diff --git a/src/storage/v3/indices.hpp b/src/storage/v3/indices.hpp
index d46fb7f38..425c9da13 100644
--- a/src/storage/v3/indices.hpp
+++ b/src/storage/v3/indices.hpp
@@ -18,7 +18,6 @@
 #include <utility>
 
 #include "storage/v3/config.hpp"
-#include "storage/v3/containers.hpp"
 #include "storage/v3/property_value.hpp"
 #include "storage/v3/transaction.hpp"
 #include "storage/v3/vertex_accessor.hpp"
diff --git a/src/storage/v3/mvcc.hpp b/src/storage/v3/mvcc.hpp
index 219491635..001f57003 100644
--- a/src/storage/v3/mvcc.hpp
+++ b/src/storage/v3/mvcc.hpp
@@ -11,9 +11,13 @@
 
 #pragma once
 
+#include <type_traits>
+#include "storage/v3/edge.hpp"
 #include "storage/v3/property_value.hpp"
 #include "storage/v3/transaction.hpp"
+#include "storage/v3/vertex.hpp"
 #include "storage/v3/view.hpp"
+#include "utils/concepts.hpp"
 
 namespace memgraph::storage::v3 {
 
@@ -77,10 +81,18 @@ inline void ApplyDeltasForRead(Transaction *transaction, const Delta *delta, Vie
 /// transaction) and returns a `bool` value indicating whether the caller can
 /// proceed with a write operation.
 template <typename TObj>
+requires utils::SameAsAnyOf<TObj, Edge, Vertex>
 inline bool PrepareForWrite(Transaction *transaction, TObj *object) {
-  if (object->delta == nullptr) return true;
+  auto *delta_holder = std::invoke([object]() -> auto * {
+    if constexpr (std::is_same_v<TObj, Vertex>) {
+      return &object->second;
+    } else {
+      return object;
+    }
+  });
+  if (delta_holder->delta == nullptr) return true;
 
-  const auto &delta_commit_info = *object->delta->commit_info;
+  const auto &delta_commit_info = *delta_holder->delta->commit_info;
   if (delta_commit_info.start_or_commit_timestamp == transaction->commit_info->start_or_commit_timestamp ||
       (delta_commit_info.is_locally_committed &&
        delta_commit_info.start_or_commit_timestamp < transaction->start_timestamp)) {
@@ -105,9 +117,17 @@ inline Delta *CreateDeleteObjectDelta(Transaction *transaction) {
 /// the delta into the object's delta list.
 /// @throw std::bad_alloc
 template <typename TObj, class... Args>
+requires utils::SameAsAnyOf<TObj, Edge, Vertex>
 inline void CreateAndLinkDelta(Transaction *transaction, TObj *object, Args &&...args) {
   auto delta = &transaction->deltas.emplace_back(std::forward<Args>(args)..., transaction->commit_info.get(),
                                                  transaction->command_id);
+  auto *delta_holder = std::invoke([object]() -> auto * {
+    if constexpr (std::is_same_v<TObj, Vertex>) {
+      return &object->second;
+    } else {
+      return object;
+    }
+  });
 
   // The operations are written in such order so that both `next` and `prev`
   // chains are valid at all times. The chains must be valid at all times
@@ -118,21 +138,21 @@ inline void CreateAndLinkDelta(Transaction *transaction, TObj *object, Args &&..
   // TODO(antaljanosbenjamin): clang-tidy detects (in my opinion a false positive) issue in
   // `Shard::Accessor::CreateEdge`.
   // NOLINTNEXTLINE(clang-analyzer-core.NullDereference)
-  delta->next = object->delta;
+  delta->next = delta_holder->delta;
   // 2. We need to set the previous delta of the new delta to the object.
   delta->prev.Set(object);
   // 3. We need to set the previous delta of the existing delta to the new
   // delta. After this point the garbage collector will be able to see the new
   // delta but won't modify it until we are done with all of our modifications.
-  if (object->delta) {
-    object->delta->prev.Set(delta);
+  if (delta_holder->delta) {
+    delta_holder->delta->prev.Set(delta);
   }
   // 4. Finally, we need to set the object's delta to the new delta. The garbage
   // collector and other transactions will acquire the object lock to read the
   // delta from the object. Because the lock is held during the whole time this
   // modification is being done, everybody else will wait until we are fully
   // done with our modification before they read the object's delta value.
-  object->delta = delta;
+  delta_holder->delta = delta;
 }
 
 }  // namespace memgraph::storage::v3
diff --git a/src/storage/v3/shard.cpp b/src/storage/v3/shard.cpp
index a77f42a76..2573110c4 100644
--- a/src/storage/v3/shard.cpp
+++ b/src/storage/v3/shard.cpp
@@ -26,7 +26,6 @@
 
 #include "io/network/endpoint.hpp"
 #include "io/time.hpp"
-#include "storage/v3/containers.hpp"
 #include "storage/v3/edge_accessor.hpp"
 #include "storage/v3/id_types.hpp"
 #include "storage/v3/indices.hpp"
@@ -39,6 +38,7 @@
 #include "storage/v3/transaction.hpp"
 #include "storage/v3/vertex.hpp"
 #include "storage/v3/vertex_accessor.hpp"
+#include "storage/v3/view.hpp"
 #include "utils/exceptions.hpp"
 #include "utils/file.hpp"
 #include "utils/logging.hpp"
@@ -79,7 +79,7 @@ auto AdvanceToVisibleVertex(VertexContainer::iterator it, VertexContainer::itera
                             std::optional<VertexAccessor> *vertex, Transaction *tx, View view, Indices *indices,
                             Config::Items config, const VertexValidator &vertex_validator) {
   while (it != end) {
-    *vertex = VertexAccessor::Create(&it->second, tx, indices, config, vertex_validator, view);
+    *vertex = VertexAccessor::Create(&*it, tx, indices, config, vertex_validator, view);
     if (!*vertex) {
       ++it;
       continue;
@@ -346,7 +346,7 @@ Shard::Accessor::Accessor(Shard &shard, Transaction &transaction)
     : shard_(&shard), transaction_(&transaction), config_(shard_->config_.items) {}
 
 ShardResult<VertexAccessor> Shard::Accessor::CreateVertexAndValidate(
-    const std::vector<LabelId> &labels, const std::vector<PropertyValue> &primary_properties,
+    const std::vector<LabelId> &labels, const PrimaryKey &primary_properties,
     const std::vector<std::pair<PropertyId, PropertyValue>> &properties) {
   OOMExceptionEnabler oom_exception;
   const auto schema = shard_->GetSchema(shard_->primary_label_)->second;
@@ -358,10 +358,10 @@ ShardResult<VertexAccessor> Shard::Accessor::CreateVertexAndValidate(
   }
 
   auto *delta = CreateDeleteObjectDelta(transaction_);
-  auto [it, inserted] = shard_->vertices_.emplace(primary_properties, Vertex(delta, primary_properties));
-  delta->prev.Set(&it->second);
+  auto [it, inserted] = shard_->vertices_.emplace(primary_properties, VertexData{delta});
+  delta->prev.Set(&*it);
 
-  VertexAccessor vertex_acc{&it->second, transaction_, &shard_->indices_, config_, shard_->vertex_validator_};
+  VertexAccessor vertex_acc{&*it, transaction_, &shard_->indices_, config_, shard_->vertex_validator_};
   if (!inserted) {
     return SHARD_ERROR(ErrorCode::VERTEX_ALREADY_INSERTED);
   }
@@ -389,7 +389,7 @@ std::optional<VertexAccessor> Shard::Accessor::FindVertex(std::vector<PropertyVa
   if (it == shard_->vertices_.end()) {
     return std::nullopt;
   }
-  return VertexAccessor::Create(&it->second, transaction_, &shard_->indices_, config_, shard_->vertex_validator_, view);
+  return VertexAccessor::Create(&*it, transaction_, &shard_->indices_, config_, shard_->vertex_validator_, view);
 }
 
 ShardResult<std::optional<VertexAccessor>> Shard::Accessor::DeleteVertex(VertexAccessor *vertex) {
@@ -400,14 +400,15 @@ ShardResult<std::optional<VertexAccessor>> Shard::Accessor::DeleteVertex(VertexA
 
   if (!PrepareForWrite(transaction_, vertex_ptr)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
 
-  if (vertex_ptr->deleted) {
+  if (vertex_ptr->second.deleted) {
     return std::optional<VertexAccessor>{};
   }
 
-  if (!vertex_ptr->in_edges.empty() || !vertex_ptr->out_edges.empty()) return SHARD_ERROR(ErrorCode::VERTEX_HAS_EDGES);
+  if (!vertex_ptr->second.in_edges.empty() || !vertex_ptr->second.out_edges.empty())
+    return SHARD_ERROR(ErrorCode::VERTEX_HAS_EDGES);
 
   CreateAndLinkDelta(transaction_, vertex_ptr, Delta::RecreateObjectTag());
-  vertex_ptr->deleted = true;
+  vertex_ptr->second.deleted = true;
 
   return std::make_optional<VertexAccessor>(vertex_ptr, transaction_, &shard_->indices_, config_,
                                             shard_->vertex_validator_, true);
@@ -422,20 +423,20 @@ ShardResult<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>>
             "accessor when deleting a vertex!");
   auto *vertex_ptr = vertex->vertex_;
 
-  std::vector<Vertex::EdgeLink> in_edges;
-  std::vector<Vertex::EdgeLink> out_edges;
+  std::vector<VertexData::EdgeLink> in_edges;
+  std::vector<VertexData::EdgeLink> out_edges;
 
   {
     if (!PrepareForWrite(transaction_, vertex_ptr)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
 
-    if (vertex_ptr->deleted) return std::optional<ReturnType>{};
+    if (vertex_ptr->second.deleted) return std::optional<ReturnType>{};
 
-    in_edges = vertex_ptr->in_edges;
-    out_edges = vertex_ptr->out_edges;
+    in_edges = vertex_ptr->second.in_edges;
+    out_edges = vertex_ptr->second.out_edges;
   }
 
   std::vector<EdgeAccessor> deleted_edges;
-  const VertexId vertex_id{shard_->primary_label_, vertex_ptr->keys};
+  const VertexId vertex_id{shard_->primary_label_, *vertex->PrimaryKey(View::OLD)};  // TODO Replace
   for (const auto &item : in_edges) {
     auto [edge_type, from_vertex, edge] = item;
     EdgeAccessor e(edge, edge_type, from_vertex, vertex_id, transaction_, &shard_->indices_, config_);
@@ -469,10 +470,10 @@ ShardResult<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>>
 
   if (!PrepareForWrite(transaction_, vertex_ptr)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
 
-  MG_ASSERT(!vertex_ptr->deleted, "Invalid database state!");
+  MG_ASSERT(!vertex_ptr->second.deleted, "Invalid database state!");
 
   CreateAndLinkDelta(transaction_, vertex_ptr, Delta::RecreateObjectTag());
-  vertex_ptr->deleted = true;
+  vertex_ptr->second.deleted = true;
 
   return std::make_optional<ReturnType>(
       VertexAccessor{vertex_ptr, transaction_, &shard_->indices_, config_, shard_->vertex_validator_, true},
@@ -494,22 +495,22 @@ ShardResult<EdgeAccessor> Shard::Accessor::CreateEdge(VertexId from_vertex_id, V
   if (from_is_local) {
     auto it = vertices.find(from_vertex_id.primary_key);
     MG_ASSERT(it != vertices.end(), "Cannot find local vertex");
-    from_vertex = &it->second;
+    from_vertex = &*it;
   }
 
   if (to_is_local) {
     auto it = vertices.find(to_vertex_id.primary_key);
     MG_ASSERT(it != vertices.end(), "Cannot find local vertex");
-    to_vertex = &it->second;
+    to_vertex = &*it;
   }
 
   if (from_is_local) {
     if (!PrepareForWrite(transaction_, from_vertex)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
-    if (from_vertex->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
+    if (from_vertex->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
   }
   if (to_is_local && to_vertex != from_vertex) {
     if (!PrepareForWrite(transaction_, to_vertex)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
-    if (to_vertex->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
+    if (to_vertex->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
   }
 
   EdgeRef edge(gid);
@@ -524,11 +525,11 @@ ShardResult<EdgeAccessor> Shard::Accessor::CreateEdge(VertexId from_vertex_id, V
 
   if (from_is_local) {
     CreateAndLinkDelta(transaction_, from_vertex, Delta::RemoveOutEdgeTag(), edge_type, to_vertex_id, edge);
-    from_vertex->out_edges.emplace_back(edge_type, to_vertex_id, edge);
+    from_vertex->second.out_edges.emplace_back(edge_type, to_vertex_id, edge);
   }
   if (to_is_local) {
     CreateAndLinkDelta(transaction_, to_vertex, Delta::RemoveInEdgeTag(), edge_type, from_vertex_id, edge);
-    to_vertex->in_edges.emplace_back(edge_type, from_vertex_id, edge);
+    from_vertex->second.in_edges.emplace_back(edge_type, from_vertex_id, edge);
   }
   // Increment edge count.
   ++shard_->edge_count_;
@@ -539,8 +540,8 @@ ShardResult<EdgeAccessor> Shard::Accessor::CreateEdge(VertexId from_vertex_id, V
 
 ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId from_vertex_id, VertexId to_vertex_id,
                                                                      const Gid edge_id) {
-  Vertex *from_vertex{nullptr};
-  Vertex *to_vertex{nullptr};
+  VertexContainer::value_type *from_vertex{nullptr};
+  VertexContainer::value_type *to_vertex{nullptr};
 
   auto &vertices = shard_->vertices_;
 
@@ -550,13 +551,13 @@ ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId fr
   if (from_is_local) {
     auto it = vertices.find(from_vertex_id.primary_key);
     MG_ASSERT(it != vertices.end(), "Cannot find local vertex");
-    from_vertex = &it->second;
+    from_vertex = &*it;
   }
 
   if (to_is_local) {
     auto it = vertices.find(to_vertex_id.primary_key);
     MG_ASSERT(it != vertices.end(), "Cannot find local vertex");
-    to_vertex = &it->second;
+    to_vertex = &*it;
   }
 
   MG_ASSERT(from_is_local || to_is_local, "Trying to delete an edge without having a local vertex");
@@ -565,13 +566,13 @@ ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId fr
     if (!PrepareForWrite(transaction_, from_vertex)) {
       return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
     }
-    MG_ASSERT(!from_vertex->deleted, "Invalid database state!");
+    MG_ASSERT(!from_vertex->second.deleted, "Invalid database state!");
   }
   if (to_is_local && to_vertex != from_vertex) {
     if (!PrepareForWrite(transaction_, to_vertex)) {
       return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
     }
-    MG_ASSERT(!to_vertex->deleted, "Invalid database state!");
+    MG_ASSERT(!to_vertex->second.deleted, "Invalid database state!");
   }
 
   const auto edge_ref = std::invoke([edge_id, this]() -> EdgeRef {
@@ -584,9 +585,9 @@ ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId fr
   });
 
   std::optional<EdgeTypeId> edge_type{};
-  auto delete_edge_from_storage = [&edge_type, &edge_ref, this](std::vector<Vertex::EdgeLink> &edges) mutable {
+  auto delete_edge_from_storage = [&edge_type, &edge_ref, this](std::vector<VertexData::EdgeLink> &edges) mutable {
     auto it = std::find_if(edges.begin(), edges.end(),
-                           [&edge_ref](const Vertex::EdgeLink &link) { return std::get<2>(link) == edge_ref; });
+                           [&edge_ref](const VertexData::EdgeLink &link) { return std::get<2>(link) == edge_ref; });
     if (config_.properties_on_edges) {
       MG_ASSERT(it != edges.end(), "Invalid database state!");
     } else if (it == edges.end()) {
@@ -598,8 +599,8 @@ ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId fr
     return true;
   };
   // NOLINTNEXTLINE(clang-analyzer-core.NonNullParamChecker)
-  auto success_on_to = to_is_local ? delete_edge_from_storage(to_vertex->in_edges) : false;
-  auto success_on_from = from_is_local ? delete_edge_from_storage(from_vertex->out_edges) : false;
+  auto success_on_to = to_is_local ? delete_edge_from_storage(to_vertex->second.in_edges) : false;
+  auto success_on_from = from_is_local ? delete_edge_from_storage(from_vertex->second.out_edges) : false;
 
   if (config_.properties_on_edges) {
     // Because of the check above, we are sure that the vertex exists.
@@ -625,10 +626,10 @@ ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId fr
   MG_ASSERT(edge_type.has_value(), "Edge type is not determined");
 
   if (from_is_local) {
-    CreateAndLinkDelta(transaction_, from_vertex, Delta::AddOutEdgeTag(), *edge_type, to_vertex_id, edge_ref);
+    CreateAndLinkDelta(transaction_, &*from_vertex, Delta::AddOutEdgeTag(), *edge_type, to_vertex_id, edge_ref);
   }
   if (to_is_local) {
-    CreateAndLinkDelta(transaction_, to_vertex, Delta::AddInEdgeTag(), *edge_type, from_vertex_id, edge_ref);
+    CreateAndLinkDelta(transaction_, &*to_vertex, Delta::AddInEdgeTag(), *edge_type, from_vertex_id, edge_ref);
   }
 
   // Decrement edge count.
@@ -690,41 +691,41 @@ void Shard::Accessor::Abort() {
     auto prev = delta.prev.Get();
     switch (prev.type) {
       case PreviousPtr::Type::VERTEX: {
-        auto *vertex = prev.vertex;
-        Delta *current = vertex->delta;
+        auto &[pk, vertex] = *prev.vertex;
+        Delta *current = vertex.delta;
         while (current != nullptr && current->commit_info->start_or_commit_timestamp == transaction_->start_timestamp) {
           switch (current->action) {
             case Delta::Action::REMOVE_LABEL: {
-              auto it = std::find(vertex->labels.begin(), vertex->labels.end(), current->label);
-              MG_ASSERT(it != vertex->labels.end(), "Invalid database state!");
-              std::swap(*it, *vertex->labels.rbegin());
-              vertex->labels.pop_back();
+              auto it = std::find(vertex.labels.begin(), vertex.labels.end(), current->label);
+              MG_ASSERT(it != vertex.labels.end(), "Invalid database state!");
+              std::swap(*it, *vertex.labels.rbegin());
+              vertex.labels.pop_back();
               break;
             }
             case Delta::Action::ADD_LABEL: {
-              auto it = std::find(vertex->labels.begin(), vertex->labels.end(), current->label);
-              MG_ASSERT(it == vertex->labels.end(), "Invalid database state!");
-              vertex->labels.push_back(current->label);
+              auto it = std::find(vertex.labels.begin(), vertex.labels.end(), current->label);
+              MG_ASSERT(it == vertex.labels.end(), "Invalid database state!");
+              vertex.labels.push_back(current->label);
               break;
             }
             case Delta::Action::SET_PROPERTY: {
-              vertex->properties.SetProperty(current->property.key, current->property.value);
+              vertex.properties.SetProperty(current->property.key, current->property.value);
               break;
             }
             case Delta::Action::ADD_IN_EDGE: {
-              Vertex::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
-                                    current->vertex_edge.edge};
-              auto it = std::find(vertex->in_edges.begin(), vertex->in_edges.end(), link);
-              MG_ASSERT(it == vertex->in_edges.end(), "Invalid database state!");
-              vertex->in_edges.push_back(link);
+              VertexData::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
+                                        current->vertex_edge.edge};
+              auto it = std::find(vertex.in_edges.begin(), vertex.in_edges.end(), link);
+              MG_ASSERT(it == vertex.in_edges.end(), "Invalid database state!");
+              vertex.in_edges.push_back(link);
               break;
             }
             case Delta::Action::ADD_OUT_EDGE: {
-              Vertex::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
-                                    current->vertex_edge.edge};
-              auto it = std::find(vertex->out_edges.begin(), vertex->out_edges.end(), link);
-              MG_ASSERT(it == vertex->out_edges.end(), "Invalid database state!");
-              vertex->out_edges.push_back(link);
+              VertexData::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
+                                        current->vertex_edge.edge};
+              auto it = std::find(vertex.out_edges.begin(), vertex.out_edges.end(), link);
+              MG_ASSERT(it == vertex.out_edges.end(), "Invalid database state!");
+              vertex.out_edges.push_back(link);
               // Increment edge count. We only increment the count here because
               // the information in `ADD_IN_EDGE` and `Edge/RECREATE_OBJECT` is
               // redundant. Also, `Edge/RECREATE_OBJECT` isn't available when
@@ -733,21 +734,21 @@ void Shard::Accessor::Abort() {
               break;
             }
             case Delta::Action::REMOVE_IN_EDGE: {
-              Vertex::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
-                                    current->vertex_edge.edge};
-              auto it = std::find(vertex->in_edges.begin(), vertex->in_edges.end(), link);
-              MG_ASSERT(it != vertex->in_edges.end(), "Invalid database state!");
-              std::swap(*it, *vertex->in_edges.rbegin());
-              vertex->in_edges.pop_back();
+              VertexData::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
+                                        current->vertex_edge.edge};
+              auto it = std::find(vertex.in_edges.begin(), vertex.in_edges.end(), link);
+              MG_ASSERT(it != vertex.in_edges.end(), "Invalid database state!");
+              std::swap(*it, *vertex.in_edges.rbegin());
+              vertex.in_edges.pop_back();
               break;
             }
             case Delta::Action::REMOVE_OUT_EDGE: {
-              Vertex::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
-                                    current->vertex_edge.edge};
-              auto it = std::find(vertex->out_edges.begin(), vertex->out_edges.end(), link);
-              MG_ASSERT(it != vertex->out_edges.end(), "Invalid database state!");
-              std::swap(*it, *vertex->out_edges.rbegin());
-              vertex->out_edges.pop_back();
+              VertexData::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
+                                        current->vertex_edge.edge};
+              auto it = std::find(vertex.out_edges.begin(), vertex.out_edges.end(), link);
+              MG_ASSERT(it != vertex.out_edges.end(), "Invalid database state!");
+              std::swap(*it, *vertex.out_edges.rbegin());
+              vertex.out_edges.pop_back();
               // Decrement edge count. We only decrement the count here because
               // the information in `REMOVE_IN_EDGE` and `Edge/DELETE_OBJECT` is
               // redundant. Also, `Edge/DELETE_OBJECT` isn't available when edge
@@ -756,20 +757,20 @@ void Shard::Accessor::Abort() {
               break;
             }
             case Delta::Action::DELETE_OBJECT: {
-              vertex->deleted = true;
-              shard_->deleted_vertices_.push_back(vertex->keys);
+              vertex.deleted = true;
+              shard_->deleted_vertices_.push_back(&pk);
               break;
             }
             case Delta::Action::RECREATE_OBJECT: {
-              vertex->deleted = false;
+              vertex.deleted = false;
               break;
             }
           }
           current = current->next;
         }
-        vertex->delta = current;
+        vertex.delta = current;
         if (current != nullptr) {
-          current->prev.Set(vertex);
+          current->prev.Set(prev.vertex);
         }
 
         break;
@@ -964,10 +965,12 @@ void Shard::CollectGarbage(const io::Time current_time) {
           auto prev = delta.prev.Get();
           switch (prev.type) {
             case PreviousPtr::Type::VERTEX: {
-              Vertex *vertex = prev.vertex;
-              vertex->delta = nullptr;
-              if (vertex->deleted) {
-                deleted_vertices_.push_back(vertex->keys);
+              // Here we need to get pk from prev pointer, and that is why change
+              // to the PrevPtr so it points to pair of pk and vertex
+              auto &[pk, vertex] = *prev.vertex;
+              vertex.delta = nullptr;
+              if (vertex.deleted) {
+                deleted_vertices_.push_back(&pk);
               }
               break;
             }
@@ -1015,7 +1018,7 @@ void Shard::CollectGarbage(const io::Time current_time) {
   }
 
   for (const auto &vertex : deleted_vertices_) {
-    MG_ASSERT(vertices_.erase(vertex), "Invalid database state!");
+    MG_ASSERT(vertices_.erase(*vertex), "Invalid database state!");
   }
   deleted_vertices_.clear();
   {
diff --git a/src/storage/v3/shard.hpp b/src/storage/v3/shard.hpp
index b998c06cc..8542d47eb 100644
--- a/src/storage/v3/shard.hpp
+++ b/src/storage/v3/shard.hpp
@@ -25,7 +25,6 @@
 #include "io/time.hpp"
 #include "kvstore/kvstore.hpp"
 #include "storage/v3/config.hpp"
-#include "storage/v3/containers.hpp"
 #include "storage/v3/edge.hpp"
 #include "storage/v3/edge_accessor.hpp"
 #include "storage/v3/id_types.hpp"
@@ -387,7 +386,7 @@ class Shard final {
 
   // Vertices that are logically deleted but still have to be removed from
   // indices before removing them from the main storage.
-  std::list<PrimaryKey> deleted_vertices_;
+  std::list<const PrimaryKey *> deleted_vertices_;
 
   // Edges that are logically deleted and wait to be removed from the main
   // storage.
diff --git a/src/storage/v3/containers.hpp b/src/storage/v3/vertex.cpp
similarity index 59%
rename from src/storage/v3/containers.hpp
rename to src/storage/v3/vertex.cpp
index 918cf3568..0dc80ad65 100644
--- a/src/storage/v3/containers.hpp
+++ b/src/storage/v3/vertex.cpp
@@ -9,16 +9,22 @@
 // by the Apache License, Version 2.0, included in the file
 // licenses/APL.txt.
 
-#pragma once
-
-#include <map>
-
-#include "storage/v3/edge.hpp"
-#include "storage/v3/id_types.hpp"
-#include "storage/v3/key_store.hpp"
 #include "storage/v3/vertex.hpp"
 
+#include <limits>
+#include <tuple>
+#include <type_traits>
+#include <vector>
+
+#include "storage/v3/delta.hpp"
+
 namespace memgraph::storage::v3 {
-using VertexContainer = std::map<PrimaryKey, Vertex>;
-using EdgeContainer = std::map<Gid, Edge>;
+
+VertexData::VertexData(Delta *delta) : delta{delta} {
+  MG_ASSERT(delta == nullptr || delta->action == Delta::Action::DELETE_OBJECT,
+            "Vertex must be created with an initial DELETE_OBJECT delta!");
+}
+
+bool VertexHasLabel(const Vertex &vertex, const LabelId label) { return utils::Contains(vertex.second.labels, label); }
+
 }  // namespace memgraph::storage::v3
diff --git a/src/storage/v3/vertex.hpp b/src/storage/v3/vertex.hpp
index 565e39d1a..f8caaa399 100644
--- a/src/storage/v3/vertex.hpp
+++ b/src/storage/v3/vertex.hpp
@@ -16,7 +16,6 @@
 #include <type_traits>
 #include <vector>
 
-#include "storage/v3/delta.hpp"
 #include "storage/v3/edge_ref.hpp"
 #include "storage/v3/id_types.hpp"
 #include "storage/v3/key_store.hpp"
@@ -28,17 +27,12 @@
 
 namespace memgraph::storage::v3 {
 
-struct Vertex {
+struct Delta;
+
+struct VertexData {
   using EdgeLink = std::tuple<EdgeTypeId, VertexId, EdgeRef>;
 
-  Vertex(Delta *delta, PrimaryKey primary_properties) : keys{std::move(primary_properties)}, delta{delta} {
-    MG_ASSERT(delta == nullptr || delta->action == Delta::Action::DELETE_OBJECT,
-              "Vertex must be created with an initial DELETE_OBJECT delta!");
-  }
-
-  friend bool operator==(const Vertex &vertex, const PrimaryKey &primary_key) { return vertex.keys == primary_key; }
-
-  PrimaryKey keys;
+  explicit VertexData(Delta *delta);
 
   std::vector<LabelId> labels;
   PropertyStore properties;
@@ -52,8 +46,11 @@ struct Vertex {
   Delta *delta;
 };
 
-static_assert(alignof(Vertex) >= 8, "The Vertex should be aligned to at least 8!");
+// static_assert(alignof(Vertex) >= 8, "The Vertex should be aligned to at least 8!");
 
-inline bool VertexHasLabel(const Vertex &vertex, const LabelId label) { return utils::Contains(vertex.labels, label); }
+using VertexContainer = std::map<PrimaryKey, VertexData>;
+using Vertex = VertexContainer::value_type;
+
+bool VertexHasLabel(const Vertex &vertex, LabelId label);
 
 }  // namespace memgraph::storage::v3
diff --git a/src/storage/v3/vertex_accessor.cpp b/src/storage/v3/vertex_accessor.cpp
index 3f3d01efb..95e0524ea 100644
--- a/src/storage/v3/vertex_accessor.cpp
+++ b/src/storage/v3/vertex_accessor.cpp
@@ -36,8 +36,8 @@ std::pair<bool, bool> IsVisible(Vertex *vertex, Transaction *transaction, View v
   bool deleted = false;
   Delta *delta = nullptr;
   {
-    deleted = vertex->deleted;
-    delta = vertex->delta;
+    deleted = vertex->second.deleted;
+    delta = vertex->second.delta;
   }
   ApplyDeltasForRead(transaction, delta, view, [&](const Delta &delta) {
     switch (delta.action) {
@@ -85,13 +85,14 @@ ShardResult<bool> VertexAccessor::AddLabel(LabelId label) {
 
   if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
 
-  if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
+  if (vertex_->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
 
-  if (std::find(vertex_->labels.begin(), vertex_->labels.end(), label) != vertex_->labels.end()) return false;
+  if (std::find(vertex_->second.labels.begin(), vertex_->second.labels.end(), label) != vertex_->second.labels.end())
+    return false;
 
   CreateAndLinkDelta(transaction_, vertex_, Delta::RemoveLabelTag(), label);
 
-  vertex_->labels.push_back(label);
+  vertex_->second.labels.push_back(label);
 
   UpdateOnAddLabel(indices_, label, vertex_, *transaction_);
 
@@ -106,13 +107,14 @@ ShardResult<bool> VertexAccessor::AddLabelAndValidate(LabelId label) {
 
   if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
 
-  if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
+  if (vertex_->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
 
-  if (std::find(vertex_->labels.begin(), vertex_->labels.end(), label) != vertex_->labels.end()) return false;
+  if (std::find(vertex_->second.labels.begin(), vertex_->second.labels.end(), label) != vertex_->second.labels.end())
+    return false;
 
   CreateAndLinkDelta(transaction_, vertex_, Delta::RemoveLabelTag(), label);
 
-  vertex_->labels.push_back(label);
+  vertex_->second.labels.push_back(label);
 
   UpdateOnAddLabel(indices_, label, vertex_, *transaction_);
 
@@ -122,15 +124,15 @@ ShardResult<bool> VertexAccessor::AddLabelAndValidate(LabelId label) {
 ShardResult<bool> VertexAccessor::RemoveLabel(LabelId label) {
   if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
 
-  if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
+  if (vertex_->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
 
-  auto it = std::find(vertex_->labels.begin(), vertex_->labels.end(), label);
-  if (it == vertex_->labels.end()) return false;
+  auto it = std::find(vertex_->second.labels.begin(), vertex_->second.labels.end(), label);
+  if (it == vertex_->second.labels.end()) return false;
 
   CreateAndLinkDelta(transaction_, vertex_, Delta::AddLabelTag(), label);
 
-  std::swap(*it, *vertex_->labels.rbegin());
-  vertex_->labels.pop_back();
+  std::swap(*it, *vertex_->second.labels.rbegin());
+  vertex_->second.labels.pop_back();
   return true;
 }
 
@@ -142,15 +144,15 @@ ShardResult<bool> VertexAccessor::RemoveLabelAndValidate(LabelId label) {
 
   if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
 
-  if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
+  if (vertex_->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
 
-  auto it = std::find(vertex_->labels.begin(), vertex_->labels.end(), label);
-  if (it == vertex_->labels.end()) return false;
+  auto it = std::find(vertex_->second.labels.begin(), vertex_->second.labels.end(), label);
+  if (it == vertex_->second.labels.end()) return false;
 
   CreateAndLinkDelta(transaction_, vertex_, Delta::AddLabelTag(), label);
 
-  std::swap(*it, *vertex_->labels.rbegin());
-  vertex_->labels.pop_back();
+  std::swap(*it, *vertex_->second.labels.rbegin());
+  vertex_->second.labels.pop_back();
   return true;
 }
 
@@ -162,9 +164,9 @@ ShardResult<bool> VertexAccessor::HasLabel(LabelId label, View view) const {
   bool has_label = false;
   Delta *delta = nullptr;
   {
-    deleted = vertex_->deleted;
+    deleted = vertex_->second.deleted;
     has_label = label == vertex_validator_->primary_label_ || VertexHasLabel(*vertex_, label);
-    delta = vertex_->delta;
+    delta = vertex_->second.delta;
   }
   ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &has_label, label](const Delta &delta) {
     switch (delta.action) {
@@ -215,14 +217,14 @@ ShardResult<PrimaryKey> VertexAccessor::PrimaryKey(const View view) const {
   if (const auto result = CheckVertexExistence(view); result.HasError()) {
     return result.GetError();
   }
-  return vertex_->keys;
+  return vertex_->first;
 }
 
 ShardResult<VertexId> VertexAccessor::Id(View view) const {
   if (const auto result = CheckVertexExistence(view); result.HasError()) {
     return result.GetError();
   }
-  return VertexId{vertex_validator_->primary_label_, vertex_->keys};
+  return VertexId{vertex_validator_->primary_label_, vertex_->first};
 };
 
 ShardResult<std::vector<LabelId>> VertexAccessor::Labels(View view) const {
@@ -231,9 +233,9 @@ ShardResult<std::vector<LabelId>> VertexAccessor::Labels(View view) const {
   std::vector<LabelId> labels;
   Delta *delta = nullptr;
   {
-    deleted = vertex_->deleted;
-    labels = vertex_->labels;
-    delta = vertex_->delta;
+    deleted = vertex_->second.deleted;
+    labels = vertex_->second.labels;
+    delta = vertex_->second.delta;
   }
   ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &labels](const Delta &delta) {
     switch (delta.action) {
@@ -278,9 +280,9 @@ ShardResult<PropertyValue> VertexAccessor::SetProperty(PropertyId property, cons
 
   if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
 
-  if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
+  if (vertex_->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
 
-  auto current_value = vertex_->properties.GetProperty(property);
+  auto current_value = vertex_->second.properties.GetProperty(property);
   // We could skip setting the value if the previous one is the same to the new
   // one. This would save some memory as a delta would not be created as well as
   // avoid copying the value. The reason we are not doing that is because the
@@ -288,7 +290,7 @@ ShardResult<PropertyValue> VertexAccessor::SetProperty(PropertyId property, cons
   // "modify in-place". Additionally, the created delta will make other
   // transactions get a SERIALIZATION_ERROR.
   CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property, current_value);
-  vertex_->properties.SetProperty(property, value);
+  vertex_->second.properties.SetProperty(property, value);
 
   UpdateOnSetProperty(indices_, property, value, vertex_, *transaction_);
 
@@ -300,8 +302,8 @@ ShardResult<void> VertexAccessor::CheckVertexExistence(View view) const {
   bool deleted = false;
   Delta *delta = nullptr;
   {
-    deleted = vertex_->deleted;
-    delta = vertex_->delta;
+    deleted = vertex_->second.deleted;
+    delta = vertex_->second.delta;
   }
   ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted](const Delta &delta) {
     switch (delta.action) {
@@ -343,11 +345,11 @@ ShardResult<PropertyValue> VertexAccessor::SetPropertyAndValidate(PropertyId pro
     return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
   }
 
-  if (vertex_->deleted) {
+  if (vertex_->second.deleted) {
     return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
   }
 
-  auto current_value = vertex_->properties.GetProperty(property);
+  auto current_value = vertex_->second.properties.GetProperty(property);
   // We could skip setting the value if the previous one is the same to the new
   // one. This would save some memory as a delta would not be created as well as
   // avoid copying the value. The reason we are not doing that is because the
@@ -355,7 +357,7 @@ ShardResult<PropertyValue> VertexAccessor::SetPropertyAndValidate(PropertyId pro
   // "modify in-place". Additionally, the created delta will make other
   // transactions get a SERIALIZATION_ERROR.
   CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property, current_value);
-  vertex_->properties.SetProperty(property, value);
+  vertex_->second.properties.SetProperty(property, value);
 
   UpdateOnSetProperty(indices_, property, value, vertex_, *transaction_);
 
@@ -365,15 +367,15 @@ ShardResult<PropertyValue> VertexAccessor::SetPropertyAndValidate(PropertyId pro
 ShardResult<std::map<PropertyId, PropertyValue>> VertexAccessor::ClearProperties() {
   if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
 
-  if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
+  if (vertex_->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
 
-  auto properties = vertex_->properties.Properties();
+  auto properties = vertex_->second.properties.Properties();
   for (const auto &property : properties) {
     CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property.first, property.second);
     UpdateOnSetProperty(indices_, property.first, PropertyValue(), vertex_, *transaction_);
   }
 
-  vertex_->properties.ClearProperties();
+  vertex_->second.properties.ClearProperties();
 
   return std::move(properties);
 }
@@ -396,11 +398,11 @@ PropertyValue VertexAccessor::GetPropertyValue(PropertyId property, View view) c
   // Find PropertyId index in keystore
   for (size_t property_index{0}; property_index < schema->second.size(); ++property_index) {
     if (schema->second[property_index].property_id == property) {
-      return vertex_->keys[property_index];
+      return vertex_->first[property_index];
     }
   }
 
-  return value = vertex_->properties.GetProperty(property);
+  return value = vertex_->second.properties.GetProperty(property);
 }
 
 ShardResult<PropertyValue> VertexAccessor::GetProperty(PropertyId property, View view) const {
@@ -409,9 +411,9 @@ ShardResult<PropertyValue> VertexAccessor::GetProperty(PropertyId property, View
   PropertyValue value;
   Delta *delta = nullptr;
   {
-    deleted = vertex_->deleted;
+    deleted = vertex_->second.deleted;
     value = GetPropertyValue(property, view);
-    delta = vertex_->delta;
+    delta = vertex_->second.delta;
   }
   ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &value, property](const Delta &delta) {
     switch (delta.action) {
@@ -453,10 +455,10 @@ ShardResult<std::map<PropertyId, PropertyValue>> VertexAccessor::Properties(View
   std::map<PropertyId, PropertyValue> properties;
   Delta *delta = nullptr;
   {
-    deleted = vertex_->deleted;
+    deleted = vertex_->second.deleted;
     // TODO(antaljanosbenjamin): Should this also return the primary key?
-    properties = vertex_->properties.Properties();
-    delta = vertex_->delta;
+    properties = vertex_->second.properties.Properties();
+    delta = vertex_->second.delta;
   }
   ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &properties](const Delta &delta) {
     switch (delta.action) {
@@ -501,14 +503,14 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const
                                                                const VertexId *destination_id) const {
   bool exists = true;
   bool deleted = false;
-  std::vector<Vertex::EdgeLink> in_edges;
+  std::vector<VertexData::EdgeLink> in_edges;
   Delta *delta = nullptr;
   {
-    deleted = vertex_->deleted;
+    deleted = vertex_->second.deleted;
     if (edge_types.empty() && nullptr == destination_id) {
-      in_edges = vertex_->in_edges;
+      in_edges = vertex_->second.in_edges;
     } else {
-      for (const auto &item : vertex_->in_edges) {
+      for (const auto &item : vertex_->second.in_edges) {
         const auto &[edge_type, from_vertex, edge] = item;
         if (nullptr != destination_id && from_vertex != *destination_id) {
           continue;
@@ -518,7 +520,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const
         in_edges.push_back(item);
       }
     }
-    delta = vertex_->delta;
+    delta = vertex_->second.delta;
   }
   ApplyDeltasForRead(
       transaction_, delta, view, [&exists, &deleted, &in_edges, &edge_types, destination_id](const Delta &delta) {
@@ -529,7 +531,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const
                 std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
               break;
             // Add the edge because we don't see the removal.
-            Vertex::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
+            VertexData::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
             auto it = std::find(in_edges.begin(), in_edges.end(), link);
             MG_ASSERT(it == in_edges.end(), "Invalid database state!");
             in_edges.push_back(link);
@@ -541,7 +543,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const
                 std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
               break;
             // Remove the label because we don't see the addition.
-            Vertex::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
+            VertexData::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
             auto it = std::find(in_edges.begin(), in_edges.end(), link);
             MG_ASSERT(it != in_edges.end(), "Invalid database state!");
             std::swap(*it, *in_edges.rbegin());
@@ -571,7 +573,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const
     return ret;
   }
   ret.reserve(in_edges.size());
-  const auto id = VertexId{vertex_validator_->primary_label_, vertex_->keys};
+  const auto id = VertexId{vertex_validator_->primary_label_, vertex_->first};
   for (const auto &item : in_edges) {
     const auto &[edge_type, from_vertex, edge] = item;
     ret.emplace_back(edge, edge_type, from_vertex, id, transaction_, indices_, config_);
@@ -583,14 +585,14 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const
                                                                 const VertexId *destination_id) const {
   bool exists = true;
   bool deleted = false;
-  std::vector<Vertex::EdgeLink> out_edges;
+  std::vector<VertexData::EdgeLink> out_edges;
   Delta *delta = nullptr;
   {
-    deleted = vertex_->deleted;
+    deleted = vertex_->second.deleted;
     if (edge_types.empty() && nullptr == destination_id) {
-      out_edges = vertex_->out_edges;
+      out_edges = vertex_->second.out_edges;
     } else {
-      for (const auto &item : vertex_->out_edges) {
+      for (const auto &item : vertex_->second.out_edges) {
         const auto &[edge_type, to_vertex, edge] = item;
         if (nullptr != destination_id && to_vertex != *destination_id) continue;
         if (!edge_types.empty() && std::find(edge_types.begin(), edge_types.end(), edge_type) == edge_types.end())
@@ -598,7 +600,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const
         out_edges.push_back(item);
       }
     }
-    delta = vertex_->delta;
+    delta = vertex_->second.delta;
   }
   ApplyDeltasForRead(
       transaction_, delta, view, [&exists, &deleted, &out_edges, &edge_types, destination_id](const Delta &delta) {
@@ -609,7 +611,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const
                 std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
               break;
             // Add the edge because we don't see the removal.
-            Vertex::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
+            VertexData::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
             auto it = std::find(out_edges.begin(), out_edges.end(), link);
             MG_ASSERT(it == out_edges.end(), "Invalid database state!");
             out_edges.push_back(link);
@@ -621,7 +623,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const
                 std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
               break;
             // Remove the label because we don't see the addition.
-            Vertex::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
+            VertexData::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
             auto it = std::find(out_edges.begin(), out_edges.end(), link);
             MG_ASSERT(it != out_edges.end(), "Invalid database state!");
             std::swap(*it, *out_edges.rbegin());
@@ -651,7 +653,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const
     return ret;
   }
   ret.reserve(out_edges.size());
-  const auto id = VertexId{vertex_validator_->primary_label_, vertex_->keys};
+  const auto id = VertexId{vertex_validator_->primary_label_, vertex_->first};
   for (const auto &item : out_edges) {
     const auto &[edge_type, to_vertex, edge] = item;
     ret.emplace_back(edge, edge_type, id, to_vertex, transaction_, indices_, config_);
@@ -665,9 +667,9 @@ ShardResult<size_t> VertexAccessor::InDegree(View view) const {
   size_t degree = 0;
   Delta *delta = nullptr;
   {
-    deleted = vertex_->deleted;
-    degree = vertex_->in_edges.size();
-    delta = vertex_->delta;
+    deleted = vertex_->second.deleted;
+    degree = vertex_->second.in_edges.size();
+    delta = vertex_->second.delta;
   }
   ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &degree](const Delta &delta) {
     switch (delta.action) {
@@ -702,9 +704,9 @@ ShardResult<size_t> VertexAccessor::OutDegree(View view) const {
   size_t degree = 0;
   Delta *delta = nullptr;
   {
-    deleted = vertex_->deleted;
-    degree = vertex_->out_edges.size();
-    delta = vertex_->delta;
+    deleted = vertex_->second.deleted;
+    degree = vertex_->second.out_edges.size();
+    delta = vertex_->second.delta;
   }
   ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &degree](const Delta &delta) {
     switch (delta.action) {