diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5908abd4d..d64df59ec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -313,7 +313,7 @@ set(memgraph_src_files
 #    ${src_dir}/snapshot/snapshoter.cpp
 #    ${src_dir}/snapshot/snapshot_encoder.cpp
 #    ${src_dir}/snapshot/snapshot_decoder.cpp
-    ${src_dir}/storage/typed_value.cpp
+    ${src_dir}/storage/property_value.cpp
     ${src_dir}/storage/locking/record_lock.cpp
 #    ${src_dir}/storage/garbage/garbage.cpp
     ${src_dir}/storage/record_accessor.cpp
@@ -333,6 +333,7 @@ set(memgraph_src_files
     ${src_dir}/database/graph_db.cpp
     ${src_dir}/database/graph_db_accessor.cpp
     ${src_dir}/query/backend/cpp/cypher_main_visitor.cpp
+    ${src_dir}/query/backend/cpp/typed_value.cpp
 )
 # -----------------------------------------------------------------------------
 
diff --git a/src/communication/bolt/v1/serialization/bolt_serializer.cpp b/src/communication/bolt/v1/serialization/bolt_serializer.cpp
index 9a5fb8b25..f059ff5fa 100644
--- a/src/communication/bolt/v1/serialization/bolt_serializer.cpp
+++ b/src/communication/bolt/v1/serialization/bolt_serializer.cpp
@@ -6,7 +6,8 @@
 #include "io/network/socket.hpp"
 
 #include "database/graph_db.hpp"
-#include "storage/typed_value_store.hpp"
+#include "storage/property_value_store.hpp"
+#include <cassert>
 
 template <class Stream>
 void bolt::BoltSerializer<Stream>::write(const VertexAccessor &vertex) {
@@ -27,13 +28,13 @@ void bolt::BoltSerializer<Stream>::write(const VertexAccessor &vertex) {
     encoder.write_string(vertex.db_accessor().label_name(label));
 
   // write the properties
-  const TypedValueStore<GraphDb::Property> &props = vertex.Properties();
+  const PropertyValueStore<GraphDb::Property> &props = vertex.Properties();
   encoder.write_map_header(props.size());
-  props.Accept(
-      [this, &vertex](const GraphDb::Property prop, const TypedValue &value) {
-        this->encoder.write(vertex.db_accessor().property_name(prop));
-        this->write(value);
-      });
+  props.Accept([this, &vertex](const GraphDb::Property prop,
+                               const PropertyValue &value) {
+    this->encoder.write(vertex.db_accessor().property_name(prop));
+    this->write(value);
+  });
 }
 
 template <class Stream>
@@ -54,32 +55,36 @@ void bolt::BoltSerializer<Stream>::write(const EdgeAccessor &edge) {
   encoder.write(edge.db_accessor().edge_type_name(edge.edge_type()));
 
   // write the property map
-  const TypedValueStore<GraphDb::Property> &props = edge.Properties();
+  const PropertyValueStore<GraphDb::Property> &props = edge.Properties();
   encoder.write_map_header(props.size());
-  props.Accept([this, &edge](GraphDb::Property prop, const TypedValue &value) {
-    this->encoder.write(edge.db_accessor().property_name(prop));
-    this->write(value);
-  });
+  props.Accept(
+      [this, &edge](GraphDb::Property prop, const PropertyValue &value) {
+        this->encoder.write(edge.db_accessor().property_name(prop));
+        this->write(value);
+      });
 }
 
 template <class Stream>
-void bolt::BoltSerializer<Stream>::write(const TypedValue &value) {
-  switch (value.type_) {
-    case TypedValue::Type::Null:
+void bolt::BoltSerializer<Stream>::write(const PropertyValue &value) {
+  switch (value.type()) {
+    case PropertyValue::Type::Null:
       encoder.write_null();
       return;
-    case TypedValue::Type::Bool:
+    case PropertyValue::Type::Bool:
       encoder.write_bool(value.Value<bool>());
       return;
-    case TypedValue::Type::String:
+    case PropertyValue::Type::String:
       encoder.write_string(value.Value<std::string>());
       return;
-    case TypedValue::Type::Int:
+    case PropertyValue::Type::Int:
       encoder.write_integer(value.Value<int>());
       return;
-    case TypedValue::Type::Float:
-      encoder.write_double(value.Value<float>());
+    case PropertyValue::Type::Double:
+      encoder.write_double(value.Value<double>());
       return;
+    case PropertyValue::Type::List:
+      // Not implemented
+      assert(false);
   }
 }
 
diff --git a/src/communication/bolt/v1/serialization/bolt_serializer.hpp b/src/communication/bolt/v1/serialization/bolt_serializer.hpp
index a05102177..574af2085 100644
--- a/src/communication/bolt/v1/serialization/bolt_serializer.hpp
+++ b/src/communication/bolt/v1/serialization/bolt_serializer.hpp
@@ -6,7 +6,7 @@
 #include "storage/edge_accessor.hpp"
 #include "storage/vertex_accessor.hpp"
 
-#include "storage/typed_value.hpp"
+#include "storage/property_value.hpp"
 
 namespace bolt {
 
@@ -46,11 +46,11 @@ class BoltSerializer {
   void write_failure(const std::map<std::string, std::string> &data);
 
   /**
-   * Writes a TypedValue (typically a property value in the edge or vertex).
+   * Writes a PropertyValue (typically a property value in the edge or vertex).
    *
    * @param value The value to write.
    */
-  void write(const TypedValue &value);
+  void write(const PropertyValue &value);
 
  protected:
   Stream &encoder;
diff --git a/src/communication/bolt/v1/serialization/record_stream.hpp b/src/communication/bolt/v1/serialization/record_stream.hpp
index e7cfb332d..cf5b0ff6e 100644
--- a/src/communication/bolt/v1/serialization/record_stream.hpp
+++ b/src/communication/bolt/v1/serialization/record_stream.hpp
@@ -118,7 +118,7 @@ class RecordStream {
     chunk();
   }
 
-  void write(const TypedValue &value) { serializer.write(value); }
+  void write(const PropertyValue &value) { serializer.write(value); }
 
   void send() { chunked_buffer.flush(); }
 
diff --git a/src/communication/bolt/v1/serialization/record_stream_mocker.hpp b/src/communication/bolt/v1/serialization/record_stream_mocker.hpp
index 4caa10eea..257ba0beb 100644
--- a/src/communication/bolt/v1/serialization/record_stream_mocker.hpp
+++ b/src/communication/bolt/v1/serialization/record_stream_mocker.hpp
@@ -61,7 +61,7 @@ class RecordStreamMocker {
   void write(const EdgeAccessor &edge) {
     messages_.back().second.write(antlrcpp::Any(edge));
   }
-  void write(const TypedValue &value) {
+  void write(const PropertyValue &value) {
     messages_.back().second.write(antlrcpp::Any(value));
   }
 
diff --git a/src/import/element_skeleton.hpp b/src/import/element_skeleton.hpp
index c14fb1b6d..ffb1e8279 100644
--- a/src/import/element_skeleton.hpp
+++ b/src/import/element_skeleton.hpp
@@ -1,8 +1,8 @@
 #pragma once
 
 #include "database/db_accessor.hpp"
-#include "storage/model/typed_value.hpp"
-#include "storage/model/typed_value_store.hpp"
+#include "storage/model/property_value.hpp"
+#include "storage/model/property_value_store.hpp"
 #include "storage/vertex_accessor.hpp"
 #include "utils/assert.hpp"
 
@@ -95,6 +95,6 @@ class ElementSkeleton {
   Option<VertexAccessor> from_va;
   Option<EdgeType const *> type;
   std::vector<Label const *> labels;
-  TypedValueStore properties_e;
-  TypedValueStore properties_v;
+  PropertyValueStore properties_e;
+  PropertyValueStore properties_v;
 };
diff --git a/src/query/backend/cpp/typed_value.cpp b/src/query/backend/cpp/typed_value.cpp
new file mode 100644
index 000000000..2574e43eb
--- /dev/null
+++ b/src/query/backend/cpp/typed_value.cpp
@@ -0,0 +1,517 @@
+#include "query/backend/cpp/typed_value.hpp"
+
+#include <fmt/format.h>
+#include <cmath>
+#include <iostream>
+#include <memory>
+
+#include "utils/assert.hpp"
+
+TypedValue::TypedValue(const PropertyValue& value) {
+  switch (value.type()) {
+    case PropertyValue::Type::Null:
+      type_ = Type::Null;
+      return;
+
+    case PropertyValue::Type::Bool:
+      type_ = Type::Bool;
+      bool_v = value.Value<bool>();
+      return;
+
+    case PropertyValue::Type::Int:
+      type_ = Type::Int;
+      int_v = value.Value<int>();
+      return;
+
+    case PropertyValue::Type::Double:
+      type_ = Type::Double;
+      double_v = value.Value<double>();
+
+    case PropertyValue::Type::String:
+      type_ = Type::String;
+      new (&string_v) std::string(value.Value<std::string>());
+
+    case PropertyValue::Type::List:
+      type_ = Type::List;
+      auto vec = value.Value<std::vector<PropertyValue>>();
+      new (&list_v) std::vector<TypedValue>(vec.begin(), vec.end());
+      return;
+  }
+
+  permanent_fail("Unsupported PropertyValue::Type");
+}
+
+TypedValue::operator PropertyValue() const {
+  switch (type_) {
+    case TypedValue::Type::Null:
+      return PropertyValue::Null;
+    case TypedValue::Type::Bool:
+      return PropertyValue(bool_v);
+    case TypedValue::Type::Int:
+      return PropertyValue(int_v);
+    case TypedValue::Type::Double:
+      return PropertyValue(double_v);
+    case TypedValue::Type::String:
+      return PropertyValue(string_v);
+    case TypedValue::Type::List:
+      return PropertyValue(
+          std::vector<PropertyValue>(list_v.begin(), list_v.end()));
+  }
+  permanent_fail("Unsupported PropertyValue::Type");
+}
+
+// Value extraction template instantiations
+template <>
+bool TypedValue::Value<bool>() const {
+  debug_assert(type_ == TypedValue::Type::Bool,
+               "Incompatible template param and type");
+  return bool_v;
+}
+
+template <>
+std::string TypedValue::Value<std::string>() const {
+  debug_assert(type_ == TypedValue::Type::String,
+               "Incompatible template param and type");
+  return string_v;
+}
+
+template <>
+int TypedValue::Value<int>() const {
+  debug_assert(type_ == TypedValue::Type::Int,
+               "Incompatible template param and type");
+  return int_v;
+}
+
+template <>
+double TypedValue::Value<double>() const {
+  debug_assert(type_ == TypedValue::Type::Double,
+               "Incompatible template param and type");
+  return double_v;
+}
+
+template <>
+std::vector<TypedValue> TypedValue::Value<std::vector<TypedValue>>() const {
+  debug_assert(type_ == TypedValue::Type::List,
+               "Incompatible template param and type");
+  return list_v;
+}
+
+TypedValue::TypedValue(const TypedValue& other) : type_(other.type_) {
+  switch (other.type_) {
+    case TypedValue::Type::Null:
+      return;
+
+    case TypedValue::Type::Bool:
+      this->bool_v = other.bool_v;
+      return;
+
+    case TypedValue::Type::String:
+      new (&string_v) std::string(other.string_v);
+      return;
+
+    case Type::Int:
+      this->int_v = other.int_v;
+      return;
+
+    case Type::Double:
+      this->double_v = other.double_v;
+      return;
+
+    case Type::List:
+      new (&list_v) std::vector<TypedValue>(other.list_v);
+      return;
+  }
+
+  permanent_fail("Unsupported TypedValue::Type");
+}
+
+std::ostream& operator<<(std::ostream& os, const TypedValue::Type type) {
+  switch (type) {
+    case TypedValue::Type::Null:
+      return os << "null";
+    case TypedValue::Type::Bool:
+      return os << "bool";
+    case TypedValue::Type::String:
+      return os << "string";
+    case TypedValue::Type::Int:
+      return os << "int";
+    case TypedValue::Type::Double:
+      return os << "double";
+    case TypedValue::Type::List:
+      return os << "list";
+  }
+  permanent_fail("Unsupported TypedValue::Type");
+}
+
+std::ostream& operator<<(std::ostream& os, const TypedValue& value) {
+  switch (value.type_) {
+    case TypedValue::Type::Null:
+      return os << "Null";
+    case TypedValue::Type::Bool:
+      return os << (value.Value<bool>() ? "true" : "false");
+    case TypedValue::Type::String:
+      return os << value.Value<std::string>();
+    case TypedValue::Type::Int:
+      return os << value.Value<int>();
+    case TypedValue::Type::Double:
+      return os << value.Value<double>();
+    case TypedValue::Type::List:
+      os << "[";
+      for (const auto& x : value.Value<std::vector<TypedValue>>()) {
+        os << x << ",";
+      }
+      return os << "]";
+  }
+  permanent_fail("Unsupported PropertyValue::Type");
+}
+
+TypedValue& TypedValue::operator=(const TypedValue& other) {
+  // set the type of this
+  this->~TypedValue();
+  type_ = other.type_;
+
+  if (this != &other) {
+    switch (other.type_) {
+      case TypedValue::Type::Null:
+      case TypedValue::Type::Bool:
+        this->bool_v = other.bool_v;
+        return *this;
+      case TypedValue::Type::String:
+        new (&string_v) std::string(other.string_v);
+        return *this;
+      case TypedValue::Type::Int:
+        this->int_v = other.int_v;
+        return *this;
+      case TypedValue::Type::Double:
+        this->double_v = other.double_v;
+        return *this;
+      case TypedValue::Type::List:
+        new (&list_v) std::vector<TypedValue>(other.list_v);
+        return *this;
+    }
+  }
+  permanent_fail("Unsupported TypedValue::Type");
+}
+
+const TypedValue TypedValue::Null = TypedValue();
+
+TypedValue::~TypedValue() {
+  switch (type_) {
+    // destructor for primitive types does nothing
+    case Type::Null:
+    case Type::Bool:
+    case Type::Int:
+    case Type::Double:
+      return;
+
+    // we need to call destructors for non primitive types since we used
+    // placement new
+    case Type::String:
+      // Clang fails to compile ~std::string. It seems it is a bug in some
+      // versions of clang. using namespace std statement solves the issue.
+      using namespace std;
+      string_v.~string();
+      return;
+    case Type::List:
+      using namespace std;
+      list_v.~vector<TypedValue>();
+      return;
+  }
+  permanent_fail("Unsupported TypedValue::Type");
+}
+
+/**
+ * Returns the double value of a value.
+ * The value MUST be either Double or Int.
+ *
+ * @param value
+ * @return
+ */
+double ToDouble(const TypedValue& value) {
+  switch (value.type()) {
+    case TypedValue::Type::Int:
+      return (double)value.Value<int>();
+    case TypedValue::Type::Double:
+      return value.Value<double>();
+
+    default:
+      permanent_fail("Unsupported TypedValue::Type");
+  }
+}
+
+TypedValue operator<(const TypedValue& a, const TypedValue& b) {
+  if (a.type() == TypedValue::Type::Bool || b.type() == TypedValue::Type::Bool)
+    throw TypedValueException("Invalid 'less' operand types({} + {})", a.type(),
+                              b.type());
+
+  if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null)
+    return TypedValue::Null;
+
+  if (a.type() == TypedValue::Type::String ||
+      b.type() == TypedValue::Type::String) {
+    if (a.type() != b.type())
+      throw TypedValueException("Invalid equality operand types({} + {})",
+                                a.type(), b.type());
+    else
+      return a.Value<std::string>() < b.Value<std::string>();
+  }
+
+  // at this point we only have int and double
+  if (a.type() == TypedValue::Type::Double ||
+      b.type() == TypedValue::Type::Double)
+    return ToDouble(a) < ToDouble(b);
+  else
+    return a.Value<int>() < b.Value<int>();
+}
+
+// TODO: 2 = "2" -> false, I don't this is handled correctly at the moment.
+TypedValue operator==(const TypedValue& a, const TypedValue& b) {
+  if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null)
+    return TypedValue::Null;
+
+  if (a.type() == TypedValue::Type::List ||
+      b.type() == TypedValue::Type::List) {
+    if (a.type() == TypedValue::Type::List &&
+        b.type() == TypedValue::Type::List) {
+      // Potential optimisation: There is no need to copies of both lists to
+      // compare them. If operator becomes a friend of TypedValue class then we
+      // can compare list_v-s directly.
+      auto list1 = a.Value<std::vector<TypedValue>>();
+      auto list2 = b.Value<std::vector<TypedValue>>();
+      if (list1.size() != list2.size()) return false;
+      for (int i = 0; i < (int)list1.size(); ++i) {
+        if (!(list1[i] == list2[i]).Value<bool>()) {
+          return false;
+        }
+      }
+      return true;
+    }
+    // We are not compatible with neo4j at this point. In neo4j 2 = [2] compares
+    // to true. That is not the end of unselfishness of developers at neo4j so
+    // they allow us to use as many braces as we want to get to the truth in
+    // list comparison, so [[2]] = [[[[[[2]]]]]] compares to true in neo4j as
+    // well. Because, why not?
+    // At memgraph we prefer sanity so [1,2] = [1,2] compares to true and
+    // 2 = [2] compares to false.
+    return false;
+  }
+
+  if (a.type() == TypedValue::Type::String ||
+      b.type() == TypedValue::Type::String) {
+    if (a.type() != b.type())
+      throw TypedValueException("Invalid equality operand types({} + {})",
+                                a.type(), b.type());
+    else
+      return a.Value<std::string>() == b.Value<std::string>();
+  }
+
+  if (a.type() == TypedValue::Type::Bool ||
+      b.type() == TypedValue::Type::Bool) {
+    if (a.type() != b.type())
+      throw TypedValueException("Invalid equality operand types({} + {})",
+                                a.type(), b.type());
+    else
+      return a.Value<bool>() == b.Value<bool>();
+  }
+  // at this point we only have int and double
+  if (a.type() == TypedValue::Type::Double ||
+      b.type() == TypedValue::Type::Double) {
+    return ToDouble(a) == ToDouble(b);
+  } else
+    return a.Value<int>() == b.Value<int>();
+}
+
+TypedValue operator!(const TypedValue& a) {
+  switch (a.type()) {
+    case TypedValue::Type::Null:
+      return TypedValue::Null;
+    case TypedValue::Type::Bool:
+      return TypedValue(!a.Value<bool>());
+
+    default:
+      throw TypedValueException("Invalid logical not operand type (!{})",
+                                a.type());
+  }
+}
+
+/**
+ * Turns a numeric or string value into a string.
+ *
+ * @param value a value.
+ * @return A string.
+ */
+std::string ValueToString(const TypedValue& value) {
+  switch (value.type()) {
+    case TypedValue::Type::String:
+      return value.Value<std::string>();
+    case TypedValue::Type::Int:
+      return std::to_string(value.Value<int>());
+    case TypedValue::Type::Double:
+      return fmt::format("{}", value.Value<double>());
+
+    // unsupported situations
+    default:
+      permanent_fail("Unsupported TypedValue::Type");
+  }
+}
+
+TypedValue operator-(const TypedValue& a) {
+  switch (a.type()) {
+    case TypedValue::Type::Null:
+      return TypedValue::Null;
+    case TypedValue::Type::Int:
+      return -a.Value<int>();
+    case TypedValue::Type::Double:
+      return -a.Value<double>();
+
+    default:
+      throw TypedValueException("Invalid unary minus operand type (-{})",
+                                a.type());
+  }
+}
+
+/**
+ * Raises a TypedValueException if the given values do not support arithmetic
+ * operations. If they do, nothing happens.
+ *
+ * @param a First value.
+ * @param b Second value.
+ * @param string_ok If or not for the given operation it's valid to work with
+ *  String values (typically it's OK only for sum).
+ *  @param op_name Name of the operation, used only for exception description,
+ *  if raised.
+ */
+inline void EnsureArithmeticallyOk(const TypedValue& a, const TypedValue& b,
+                                   bool string_ok, const std::string& op_name) {
+  if (a.type() == TypedValue::Type::Bool || b.type() == TypedValue::Type::Bool)
+    throw TypedValueException("Invalid {} operand types {}, {}", op_name,
+                              a.type(), b.type());
+
+  if (string_ok) return;
+
+  if (a.type() == TypedValue::Type::String ||
+      b.type() == TypedValue::Type::String)
+    throw TypedValueException("Invalid subtraction operands types {}, {}",
+                              a.type(), b.type());
+}
+
+TypedValue operator+(const TypedValue& a, const TypedValue& b) {
+  if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null)
+    return TypedValue::Null;
+
+  if (a.type() == TypedValue::Type::List ||
+      b.type() == TypedValue::Type::List) {
+    std::vector<TypedValue> list;
+    auto append_list = [&list](const TypedValue& v) {
+      if (v.type() == TypedValue::Type::List) {
+        auto list2 = v.Value<std::vector<TypedValue>>();
+        list.insert(list.end(), list2.begin(), list2.end());
+      } else {
+        list.push_back(v);
+      }
+    };
+    append_list(a);
+    append_list(b);
+    return TypedValue(list);
+  }
+
+  EnsureArithmeticallyOk(a, b, true, "addition");
+  // no more Bool nor Null, summing works on anything from here onward
+
+  if (a.type() == TypedValue::Type::String ||
+      b.type() == TypedValue::Type::String)
+    return ValueToString(a) + ValueToString(b);
+
+  // at this point we only have int and double
+  if (a.type() == TypedValue::Type::Double ||
+      b.type() == TypedValue::Type::Double) {
+    return ToDouble(a) + ToDouble(b);
+  } else
+    return a.Value<int>() + b.Value<int>();
+}
+
+TypedValue operator-(const TypedValue& a, const TypedValue& b) {
+  EnsureArithmeticallyOk(a, b, false, "subtraction");
+
+  if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null)
+    return TypedValue::Null;
+
+  // at this point we only have int and double
+  if (a.type() == TypedValue::Type::Double ||
+      b.type() == TypedValue::Type::Double) {
+    return ToDouble(a) - ToDouble(b);
+  } else
+    return a.Value<int>() - b.Value<int>();
+}
+
+TypedValue operator/(const TypedValue& a, const TypedValue& b) {
+  EnsureArithmeticallyOk(a, b, false, "division");
+
+  if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null)
+    return TypedValue::Null;
+
+  // at this point we only have int and double
+  if (a.type() == TypedValue::Type::Double ||
+      b.type() == TypedValue::Type::Double) {
+    return ToDouble(a) / ToDouble(b);
+  } else
+    return a.Value<int>() / b.Value<int>();
+}
+
+TypedValue operator*(const TypedValue& a, const TypedValue& b) {
+  EnsureArithmeticallyOk(a, b, false, "multiplication");
+
+  if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null)
+    return TypedValue::Null;
+
+  // at this point we only have int and double
+  if (a.type() == TypedValue::Type::Double ||
+      b.type() == TypedValue::Type::Double) {
+    return ToDouble(a) * ToDouble(b);
+  } else
+    return a.Value<int>() * b.Value<int>();
+}
+
+TypedValue operator%(const TypedValue& a, const TypedValue& b) {
+  EnsureArithmeticallyOk(a, b, false, "modulo");
+
+  if (a.type() == TypedValue::Type::Null || b.type() == TypedValue::Type::Null)
+    return TypedValue::Null;
+
+  // at this point we only have int and double
+  if (a.type() == TypedValue::Type::Double ||
+      b.type() == TypedValue::Type::Double) {
+    return (double)fmod(ToDouble(a), ToDouble(b));
+  } else
+    return a.Value<int>() % b.Value<int>();
+}
+
+inline bool IsLogicallyOk(const TypedValue& a) {
+  return a.type() == TypedValue::Type::Bool ||
+         a.type() == TypedValue::Type::Null;
+}
+
+// TODO: Fix bugs in && and ||. null or true -> true; false and null -> false
+TypedValue operator&&(const TypedValue& a, const TypedValue& b) {
+  if (IsLogicallyOk(a) && IsLogicallyOk(b)) {
+    if (a.type() == TypedValue::Type::Null ||
+        b.type() == TypedValue::Type::Null)
+      return TypedValue::Null;
+    else
+      return a.Value<bool>() && b.Value<bool>();
+  } else
+    throw TypedValueException("Invalid logical and operand types({} && {})",
+                              a.type(), b.type());
+}
+
+TypedValue operator||(const TypedValue& a, const TypedValue& b) {
+  if (IsLogicallyOk(a) && IsLogicallyOk(b)) {
+    if (a.type() == TypedValue::Type::Null ||
+        b.type() == TypedValue::Type::Null)
+      return TypedValue::Null;
+    else
+      return a.Value<bool>() || b.Value<bool>();
+  } else
+    throw TypedValueException("Invalid logical and operand types({} && {})",
+                              a.type(), b.type());
+}
diff --git a/src/storage/typed_value.hpp b/src/query/backend/cpp/typed_value.hpp
similarity index 73%
rename from src/storage/typed_value.hpp
rename to src/query/backend/cpp/typed_value.hpp
index 49c878e21..77c0dc6f1 100644
--- a/src/storage/typed_value.hpp
+++ b/src/query/backend/cpp/typed_value.hpp
@@ -8,6 +8,7 @@
 #include "utils/exceptions/stacktrace_exception.hpp"
 #include "utils/total_ordering.hpp"
 #include "utils/underlying_cast.hpp"
+#include "storage/property_value.hpp"
 
 /**
  * Encapsulation of a value and it's type encapsulated in a class that has no
@@ -23,7 +24,7 @@ class TypedValue : public TotalOrdering<TypedValue, TypedValue, TypedValue> {
 
  public:
   /** A value type. Each type corresponds to exactly one C++ type */
-  enum class Type : unsigned { Null, String, Bool, Int, Float };
+  enum class Type : unsigned { Null, String, Bool, Int, Double, List };
 
   // single static reference to Null, used whenever Null should be returned
   static const TypedValue Null;
@@ -31,23 +32,30 @@ class TypedValue : public TotalOrdering<TypedValue, TypedValue, TypedValue> {
   // constructors for primitive types
   TypedValue(bool value) : type_(Type::Bool) { bool_v = value; }
   TypedValue(int value) : type_(Type::Int) { int_v = value; }
-  TypedValue(float value) : type_(Type::Float) { float_v = value; }
+  TypedValue(double value) : type_(Type::Double) { double_v = value; }
+
+  // conversion function to PropertyValue
+  operator PropertyValue() const;
 
   /// constructors for non-primitive types (shared pointers)
   TypedValue(const std::string& value) : type_(Type::String) {
-    new (&string_v) std::shared_ptr<std::string>(new std::string(value));
+    new (&string_v) std::string(value);
   }
   TypedValue(const char* value) : type_(Type::String) {
-    new (&string_v) std::shared_ptr<std::string>(new std::string(value));
+    new (&string_v) std::string(value);
   }
+  TypedValue(const std::vector<TypedValue>& value) : type_(Type::List) {
+    new (&list_v) std::vector<TypedValue>(value);
+  }
+  TypedValue(const PropertyValue& value);
 
   // assignment ops
-  TypedValue& operator=(TypedValue& other);
-  TypedValue& operator=(TypedValue&& other);
+  TypedValue& operator=(const TypedValue& other);
 
   TypedValue(const TypedValue& other);
   ~TypedValue();
 
+  Type type() const { return type_; }
   /**
    * Returns the value of the property as given type T.
    * The behavior of this function is undefined if
@@ -61,19 +69,26 @@ class TypedValue : public TotalOrdering<TypedValue, TypedValue, TypedValue> {
 
   friend std::ostream& operator<<(std::ostream& stream, const TypedValue& prop);
 
-  /**
-   * The Type of property.
-   */
-  const Type type_;
-
  private:
   // storage for the value of the property
   union {
     bool bool_v;
     int int_v;
-    float float_v;
-    std::shared_ptr<std::string> string_v;
+    double double_v;
+    // Since this is used in query runtime, size of union is not critical so
+    // string and vector are used instead of pointers. It requires copy of data,
+    // but most of algorithms (concatenations, serialisation...) has linear time
+    // complexity so it shouldn't be a problem. This is maybe even faster
+    // because of data locality.
+    std::string string_v;
+    std::vector<TypedValue> list_v;
+    // Node, Edge, Path, Map missing.
   };
+
+  /**
+   * The Type of property.
+   */
+  Type type_;
 };
 
 /**
diff --git a/src/query/plan_interface.hpp b/src/query/plan_interface.hpp
index 66eaa490b..4afeb01b1 100644
--- a/src/query/plan_interface.hpp
+++ b/src/query/plan_interface.hpp
@@ -24,7 +24,7 @@ class PlanInterface {
    *
    * @return bool status after execution (success OR fail)
    */
-  virtual bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  virtual bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
                    Stream &stream) = 0;
 
   /**
diff --git a/src/query/stripped.hpp b/src/query/stripped.hpp
index ec2a2935a..24f0d3b2c 100644
--- a/src/query/stripped.hpp
+++ b/src/query/stripped.hpp
@@ -1,6 +1,6 @@
 #pragma once
 
-#include "storage/typed_value_store.hpp"
+#include "storage/property_value_store.hpp"
 #include "utils/hashing/fnv.hpp"
 
 /*
@@ -10,10 +10,10 @@
 *     * hash of stripped query
 */
 struct StrippedQuery {
-  StrippedQuery(const std::string &&query, TypedValueStore<> &&arguments,
+  StrippedQuery(const std::string &&query, PropertyValueStore<> &&arguments,
                 HashType hash)
       : query(std::forward<const std::string>(query)),
-        arguments(std::forward<TypedValueStore<>>(arguments)),
+        arguments(std::forward<PropertyValueStore<>>(arguments)),
         hash(hash) {}
 
   /**
@@ -38,7 +38,7 @@ struct StrippedQuery {
   /**
    * Stripped arguments
    */
-  const TypedValueStore<> arguments;
+  const PropertyValueStore<> arguments;
 
   /**
    * Hash based on stripped query.
diff --git a/src/query/stripper.hpp b/src/query/stripper.hpp
index dcff02b66..464186ebf 100644
--- a/src/query/stripper.hpp
+++ b/src/query/stripper.hpp
@@ -9,7 +9,7 @@
 
 #include "logging/loggable.hpp"
 #include "query/stripped.hpp"
-#include "storage/typed_value_store.hpp"
+#include "storage/property_value_store.hpp"
 #include "utils/hashing/fnv.hpp"
 #include "utils/string/transform.hpp"
 #include "utils/variadic/variadic.hpp"
@@ -54,7 +54,7 @@ class QueryStripper : public Loggable {
     CommonTokenStream tokens(&lexer);
 
     // initialize data structures that will be populated
-    TypedValueStore<> stripped_arguments;
+    PropertyValueStore<> stripped_arguments;
     std::string stripped_query;
     stripped_query.reserve(query.size());
 
diff --git a/src/storage/edge.hpp b/src/storage/edge.hpp
index 0d202f2ae..e6a3a816e 100644
--- a/src/storage/edge.hpp
+++ b/src/storage/edge.hpp
@@ -3,7 +3,7 @@
 #include "database/graph_db.hpp"
 #include "mvcc/record.hpp"
 #include "mvcc/version_list.hpp"
-#include "storage/typed_value_store.hpp"
+#include "storage/property_value_store.hpp"
 
 // forward declare Vertex because there is a circular usage Edge <-> Vertex
 class Vertex;
@@ -17,5 +17,5 @@ class Edge : public mvcc::Record<Edge> {
   mvcc::VersionList<Vertex>& from_;
   mvcc::VersionList<Vertex>& to_;
   GraphDb::EdgeType edge_type_;
-  TypedValueStore<GraphDb::Property> properties_;
+  PropertyValueStore<GraphDb::Property> properties_;
 };
diff --git a/src/storage/property_value.cpp b/src/storage/property_value.cpp
new file mode 100644
index 000000000..be7ac014f
--- /dev/null
+++ b/src/storage/property_value.cpp
@@ -0,0 +1,163 @@
+#include "storage/property_value.hpp"
+
+#include <fmt/format.h>
+#include <cmath>
+#include <iostream>
+#include <memory>
+
+#include "utils/assert.hpp"
+
+// Value extraction template instantiations
+template <>
+bool PropertyValue::Value<bool>() const {
+  debug_assert(type_ == PropertyValue::Type::Bool,
+               "Incompatible template param and type");
+  return bool_v;
+}
+
+template <>
+std::string PropertyValue::Value<std::string>() const {
+  debug_assert(type_ == PropertyValue::Type::String,
+               "Incompatible template param and type");
+  return *string_v;
+}
+
+template <>
+int PropertyValue::Value<int>() const {
+  debug_assert(type_ == PropertyValue::Type::Int,
+               "Incompatible template param and type");
+  return int_v;
+}
+
+template <>
+double PropertyValue::Value<double>() const {
+  debug_assert(type_ == PropertyValue::Type::Double,
+               "Incompatible template param and type");
+  return double_v;
+}
+
+template <>
+std::vector<PropertyValue> PropertyValue::Value<std::vector<PropertyValue>>()
+    const {
+  debug_assert(type_ == PropertyValue::Type::List,
+               "Incompatible template param and type");
+  return *list_v;
+}
+
+PropertyValue::PropertyValue(const PropertyValue& other) : type_(other.type_) {
+  switch (other.type_) {
+    case PropertyValue::Type::Null:
+      return;
+
+    case PropertyValue::Type::Bool:
+      this->bool_v = other.bool_v;
+      return;
+
+    case PropertyValue::Type::String:
+      new (&string_v) std::shared_ptr<std::string>(other.string_v);
+      return;
+
+    case Type::Int:
+      this->int_v = other.int_v;
+      return;
+
+    case Type::Double:
+      this->double_v = other.double_v;
+      return;
+
+    case PropertyValue::Type::List:
+      new (&list_v) std::shared_ptr<std::vector<PropertyValue>>(other.list_v);
+      return;
+  }
+
+  permanent_fail("Unsupported PropertyValue::Type");
+}
+
+std::ostream& operator<<(std::ostream& os, const PropertyValue::Type type) {
+  switch (type) {
+    case PropertyValue::Type::Null:
+      return os << "null";
+    case PropertyValue::Type::Bool:
+      return os << "bool";
+    case PropertyValue::Type::String:
+      return os << "string";
+    case PropertyValue::Type::Int:
+      return os << "int";
+    case PropertyValue::Type::Double:
+      return os << "double";
+    case PropertyValue::Type::List:
+      return os << "list";
+  }
+  permanent_fail("Unsupported PropertyValue::Type");
+}
+
+std::ostream& operator<<(std::ostream& os, const PropertyValue& value) {
+  switch (value.type_) {
+    case PropertyValue::Type::Null:
+      return os << "Null";
+    case PropertyValue::Type::Bool:
+      return os << (value.Value<bool>() ? "true" : "false");
+    case PropertyValue::Type::String:
+      return os << value.Value<std::string>();
+    case PropertyValue::Type::Int:
+      return os << value.Value<int>();
+    case PropertyValue::Type::Double:
+      return os << value.Value<double>();
+    case PropertyValue::Type::List:
+      os << "[";
+      for (const auto& x : value.Value<std::vector<PropertyValue>>()) {
+        os << x << ",";
+      }
+      return os << "]";
+  }
+  permanent_fail("Unsupported PropertyValue::Type");
+}
+
+PropertyValue& PropertyValue::operator=(const PropertyValue& other) {
+  this->~PropertyValue();
+  type_ = other.type_;
+
+  if (this != &other) {
+    switch (other.type_) {
+      case PropertyValue::Type::Null:
+      case PropertyValue::Type::Bool:
+        this->bool_v = other.bool_v;
+        return *this;
+      case PropertyValue::Type::String:
+        new (&string_v) std::shared_ptr<std::string>(other.string_v);
+        return *this;
+      case PropertyValue::Type::Int:
+        this->int_v = other.int_v;
+        return *this;
+      case PropertyValue::Type::Double:
+        this->double_v = other.double_v;
+        return *this;
+      case PropertyValue::Type::List:
+        new (&list_v) std::shared_ptr<std::vector<PropertyValue>>(other.list_v);
+        return *this;
+    }
+  }
+  permanent_fail("Unsupported PropertyValue::Type");
+}
+
+const PropertyValue PropertyValue::Null = PropertyValue();
+
+PropertyValue::~PropertyValue() {
+  switch (type_) {
+    // destructor for primitive types does nothing
+    case Type::Null:
+    case Type::Bool:
+    case Type::Int:
+    case Type::Double:
+      return;
+
+    // destructor for shared pointer must release
+    case Type::String:
+      string_v.~shared_ptr<std::string>();
+      return;
+    case Type::List:
+      list_v.~shared_ptr<std::vector<PropertyValue>>();
+      return;
+  }
+  permanent_fail("Unsupported PropertyValue::Type");
+}
diff --git a/src/storage/property_value.hpp b/src/storage/property_value.hpp
new file mode 100644
index 000000000..35c19a751
--- /dev/null
+++ b/src/storage/property_value.hpp
@@ -0,0 +1,99 @@
+#pragma once
+
+#include <cassert>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "utils/exceptions/stacktrace_exception.hpp"
+#include "utils/total_ordering.hpp"
+#include "utils/underlying_cast.hpp"
+
+/**
+ * Encapsulation of a value and it's type encapsulated in a class that has no
+ * compiled-time info about that type.
+ *
+ * Values can be of a number of predefined types that are enumerated in
+ * PropertyValue::Type. Each such type corresponds to exactly one C++ type.
+ */
+class PropertyValue {
+ private:
+  /** Private default constructor, makes Null */
+  PropertyValue() : type_(Type::Null) {}
+
+ public:
+  /** A value type. Each type corresponds to exactly one C++ type */
+  enum class Type : unsigned { Null, String, Bool, Int, Double, List };
+
+  // single static reference to Null, used whenever Null should be returned
+  static const PropertyValue Null;
+
+  // constructors for primitive types
+  PropertyValue(bool value) : type_(Type::Bool) { bool_v = value; }
+  PropertyValue(int value) : type_(Type::Int) { int_v = value; }
+  PropertyValue(double value) : type_(Type::Double) { double_v = value; }
+
+  /// constructors for non-primitive types (shared pointers)
+  PropertyValue(const std::string& value) : type_(Type::String) {
+    new (&string_v) std::shared_ptr<std::string>(new std::string(value));
+  }
+  PropertyValue(const char* value) : type_(Type::String) {
+    new (&string_v) std::shared_ptr<std::string>(new std::string(value));
+  }
+  PropertyValue(const std::vector<PropertyValue>& value) : type_(Type::List) {
+    new (&list_v) std::shared_ptr<std::vector<PropertyValue>>(
+        new std::vector<PropertyValue>(value));
+  }
+
+  // assignment op
+  PropertyValue& operator=(const PropertyValue& other);
+
+  PropertyValue(const PropertyValue& other);
+  ~PropertyValue();
+
+  Type type() const { return type_; }
+  /**
+   * Returns the value of the property as given type T.
+   * The behavior of this function is undefined if
+   * T does not correspond to this property's type_.
+   *
+   * @tparam T Type to interpret the value as.
+   * @return The value as type T.
+   */
+  template <typename T>
+  T Value() const;
+
+  friend std::ostream& operator<<(std::ostream& stream,
+                                  const PropertyValue& prop);
+
+ private:
+  // storage for the value of the property
+  union {
+    bool bool_v;
+    int int_v;
+    double double_v;
+    std::shared_ptr<std::string> string_v;
+    // We support lists of values of different types, neo4j supports lists of
+    // values of the same type.
+    std::shared_ptr<std::vector<PropertyValue>> list_v;
+  };
+
+  /**
+   * The Type of property.
+   */
+  Type type_;
+};
+
+/**
+ * An exception raised by the PropertyValue system. Typically when
+ * trying to perform operations (such as addition) on PropertyValues
+ * of incompatible Types.
+ */
+class PropertyValueException : public StacktraceException {
+ public:
+  using ::StacktraceException::StacktraceException;
+};
+
+// stream output
+std::ostream& operator<<(std::ostream& os, const PropertyValue::Type type);
diff --git a/src/storage/typed_value_store.hpp b/src/storage/property_value_store.hpp
similarity index 76%
rename from src/storage/typed_value_store.hpp
rename to src/storage/property_value_store.hpp
index 2efe30eab..9bde3d204 100644
--- a/src/storage/typed_value_store.hpp
+++ b/src/storage/property_value_store.hpp
@@ -4,7 +4,7 @@
 #include <map>
 #include <vector>
 
-#include "typed_value.hpp"
+#include "property_value.hpp"
 
 /**
  * A collection of properties accessed in a map-like way
@@ -15,33 +15,33 @@
   * @tparam TKey The type of key used in this value store.
  */
 template <typename TKey = uint32_t>
-class TypedValueStore {
+class PropertyValueStore {
  public:
-  using sptr = std::shared_ptr<TypedValueStore>;
+  using sptr = std::shared_ptr<PropertyValueStore>;
 
   /**
-   * Returns a TypedValue (by reference) at the given key.
+   * Returns a PropertyValue (by reference) at the given key.
    * If the key does not exist, the Null property is returned.
    *
    * This is NOT thread-safe, the reference might not be valid
    * when used in a multithreaded scenario.
    *
-   * @param key The key for which a TypedValue is sought.
+   * @param key The key for which a PropertyValue is sought.
    * @return  See above.
    */
-  const TypedValue &at(const TKey &key) const {
+  const PropertyValue &at(const TKey &key) const {
     for (const auto &kv : props_)
       if (kv.first == key) return kv.second;
 
-    return TypedValue::Null;
+    return PropertyValue::Null;
   }
 
   /**
-   * Sets the value for the given key. A new TypedValue instance
+   * Sets the value for the given key. A new PropertyValue instance
    * is created for the given value (which is of raw type).
    *
    * @tparam TValue Type of value. It must be one of the
-   * predefined possible TypedValue values (bool, string, int...)
+   * predefined possible PropertyValue values (bool, string, int...)
    * @param key  The key for which the property is set. The previous
    * value at the same key (if there was one) is replaced.
    * @param value  The value to set.
@@ -50,7 +50,7 @@ class TypedValueStore {
   void set(const TKey &key, const TValue &value) {
     for (auto &kv : props_)
       if (kv.first == key) {
-        kv.second = TypedValue(value);
+        kv.second = PropertyValue(value);
         return;
       }
 
@@ -71,7 +71,7 @@ class TypedValueStore {
   void set(const TKey &key, const char *value) { set(key, std::string(value)); }
 
   /**
-   * Removes the TypedValue for the given key.
+   * Removes the PropertyValue for the given key.
    *
    * @param key The key for which to remove the property.
    * @return  The number of removed properties (0 or 1).
@@ -79,7 +79,7 @@ class TypedValueStore {
   size_t erase(const TKey &key) {
     auto found = std::find_if(
         props_.begin(), props_.end(),
-        [&key](std::pair<TKey, TypedValue> &kv) { return kv.first == key; });
+        [&key](std::pair<TKey, PropertyValue> &kv) { return kv.first == key; });
 
     if (found != props_.end()) {
       props_.erase(found);
@@ -110,10 +110,10 @@ class TypedValueStore {
   /**
    * Accepts two functions.
    *
-   * @param handler  Called for each TypedValue in this collection.
+   * @param handler  Called for each PropertyValue in this collection.
    * @param finish Called once in the end.
    */
-  void Accept(std::function<void(const TKey, const TypedValue &)> handler,
+  void Accept(std::function<void(const TKey, const PropertyValue &)> handler,
               std::function<void()> finish = {}) const {
     if (handler)
       for (const auto &prop : props_) handler(prop.first, prop.second);
@@ -122,5 +122,5 @@ class TypedValueStore {
   }
 
  private:
-  std::vector<std::pair<TKey, TypedValue>> props_;
+  std::vector<std::pair<TKey, PropertyValue>> props_;
 };
diff --git a/src/storage/typed_value_utils.hpp b/src/storage/property_value_utils.hpp
similarity index 66%
rename from src/storage/typed_value_utils.hpp
rename to src/storage/property_value_utils.hpp
index 46e9167fb..5f4c4fe14 100644
--- a/src/storage/typed_value_utils.hpp
+++ b/src/storage/property_value_utils.hpp
@@ -6,7 +6,7 @@
 #pragma once
 
 #include <ostream>
-#include "storage/typed_value_store.hpp"
+#include "storage/property_value_store.hpp"
 
 /**
  * Writes all of the values from the given store in JSON format
@@ -15,12 +15,12 @@
  * @param store The store that should be serialized to JSON.
  * @param ostream The stream to write to.
  */
-void TypedValuesToJson(const TypedValueStore& store,
+void PropertyValuesToJson(const PropertyValueStore& store,
                        std::ostream& ostream = std::cout) {
   bool first = true;
 
   auto write_key = [&ostream,
-                    &first](const TypedValueStore::TKey& key) -> std::ostream& {
+                    &first](const PropertyValueStore::TKey& key) -> std::ostream& {
     if (first) {
       ostream << '{';
       first = false;
@@ -30,21 +30,21 @@ void TypedValuesToJson(const TypedValueStore& store,
     return ostream << '"' << key << "\":";
   };
 
-  auto handler = [&ostream, &write_key](const TypedValueStore::TKey& key,
-                                        const TypedValue& value) {
+  auto handler = [&ostream, &write_key](const PropertyValueStore::TKey& key,
+                                        const PropertyValue& value) {
     switch (value.type_) {
-      case TypedValue::Type::Null:
+      case PropertyValue::Type::Null:
         break;
-      case TypedValue::Type::Bool:
+      case PropertyValue::Type::Bool:
         write_key(key) << (value.Value<bool>() ? "true" : "false");
         break;
-      case TypedValue::Type::String:
+      case PropertyValue::Type::String:
         write_key(key) << '"' << value.Value<std::string>() << '"';
         break;
-      case TypedValue::Type::Int:
+      case PropertyValue::Type::Int:
         write_key(key) << value.Value<int>();
         break;
-      case TypedValue::Type::Float:
+      case PropertyValue::Type::Float:
         write_key(key) << value.Value<float>();
         break;
     }
diff --git a/src/storage/record_accessor.cpp b/src/storage/record_accessor.cpp
index 999cb9ad5..acaded787 100644
--- a/src/storage/record_accessor.cpp
+++ b/src/storage/record_accessor.cpp
@@ -21,7 +21,7 @@ RecordAccessor<TRecord>::RecordAccessor(mvcc::VersionList<TRecord> &vlist,
 }
 
 template <typename TRecord>
-const TypedValue &RecordAccessor<TRecord>::PropsAt(
+const PropertyValue &RecordAccessor<TRecord>::PropsAt(
     GraphDb::Property key) const {
   return view().properties_.at(key);
 }
@@ -32,14 +32,14 @@ size_t RecordAccessor<TRecord>::PropsErase(GraphDb::Property key) {
 }
 
 template <typename TRecord>
-const TypedValueStore<GraphDb::Property> &RecordAccessor<TRecord>::Properties()
+const PropertyValueStore<GraphDb::Property> &RecordAccessor<TRecord>::Properties()
     const {
   return view().properties_;
 }
 
 template <typename TRecord>
 void RecordAccessor<TRecord>::PropertiesAccept(
-    std::function<void(const GraphDb::Property key, const TypedValue &prop)>
+    std::function<void(const GraphDb::Property key, const PropertyValue &prop)>
         handler,
     std::function<void()> finish) const {
   view().properties_.Accept(handler, finish);
diff --git a/src/storage/record_accessor.hpp b/src/storage/record_accessor.hpp
index 25e0cdf90..88a34e643 100644
--- a/src/storage/record_accessor.hpp
+++ b/src/storage/record_accessor.hpp
@@ -3,10 +3,10 @@
 #include "database/graph_db.hpp"
 #include "database/graph_db_accessor.hpp"
 #include "mvcc/version_list.hpp"
-#include "storage/typed_value.hpp"
+#include "storage/property_value.hpp"
 #include "utils/pass_key.hpp"
 
-#include "storage/typed_value_store.hpp"
+#include "storage/property_value_store.hpp"
 
 /**
  * An accessor to a database record (an Edge or a Vertex).
@@ -54,7 +54,7 @@ class RecordAccessor {
    * @param key
    * @return
    */
-  const TypedValue& PropsAt(GraphDb::Property key) const;
+  const PropertyValue& PropsAt(GraphDb::Property key) const;
 
   /**
    * Sets a value on the record for the given property.
@@ -80,10 +80,10 @@ class RecordAccessor {
    * Returns the properties of this record.
    * @return
    */
-  const TypedValueStore<GraphDb::Property>& Properties() const;
+  const PropertyValueStore<GraphDb::Property>& Properties() const;
 
   void PropertiesAccept(
-      std::function<void(const GraphDb::Property key, const TypedValue& prop)>
+      std::function<void(const GraphDb::Property key, const PropertyValue& prop)>
           handler,
       std::function<void()> finish = {}) const;
 
diff --git a/src/storage/typed_value.cpp b/src/storage/typed_value.cpp
deleted file mode 100644
index a0cac33bd..000000000
--- a/src/storage/typed_value.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-#include <fmt/format.h>
-#include <cmath>
-#include <iostream>
-#include <memory>
-
-#include "storage/typed_value.hpp"
-#include "utils/assert.hpp"
-
-// Value extraction template instantiations
-template <>
-bool TypedValue::Value<bool>() const {
-  debug_assert(type_ == TypedValue::Type::Bool,
-                 "Incompatible template param and type");
-  return bool_v;
-}
-
-template <>
-std::string TypedValue::Value<std::string>() const {
-  debug_assert(type_ == TypedValue::Type::String,
-                 "Incompatible template param and type");
-  return *string_v;
-}
-
-template <>
-int TypedValue::Value<int>() const {
-  debug_assert(type_ == TypedValue::Type::Int,
-                 "Incompatible template param and type");
-  return int_v;
-}
-
-template <>
-float TypedValue::Value<float>() const {
-  debug_assert(type_ == TypedValue::Type::Float,
-                 "Incompatible template param and type");
-  return float_v;
-}
-
-TypedValue::TypedValue(const TypedValue& other) : type_(other.type_) {
-  switch (other.type_) {
-    case TypedValue::Type::Null:
-      return;
-
-    case TypedValue::Type::Bool:
-      this->bool_v = other.bool_v;
-      return;
-
-    case TypedValue::Type::String:
-      new (&string_v) std::shared_ptr<std::string>(other.string_v);
-      return;
-
-    case Type::Int:
-      this->int_v = other.int_v;
-      return;
-
-    case Type::Float:
-      this->float_v = other.float_v;
-      return;
-  }
-
-  permanent_fail("Unsupported TypedValue::Type");
-}
-
-std::ostream& operator<<(std::ostream& os, const TypedValue::Type type) {
-  switch (type) {
-    case TypedValue::Type::Null:
-      return os << "null";
-    case TypedValue::Type::Bool:
-      return os << "bool";
-    case TypedValue::Type::String:
-      return os << "string";
-    case TypedValue::Type::Int:
-      return os << "int";
-    case TypedValue::Type::Float:
-      return os << "float";
-  }
-  permanent_fail("Unsupported TypedValue::Type");
-}
-
-std::ostream& operator<<(std::ostream& os, const TypedValue& value) {
-  switch (value.type_) {
-    case TypedValue::Type::Null:
-      return os << "Null";
-    case TypedValue::Type::Bool:
-      return os << (value.Value<bool>() ? "true" : "false");
-    case TypedValue::Type::String:
-      return os << value.Value<std::string>();
-    case TypedValue::Type::Int:
-      return os << value.Value<int>();
-    case TypedValue::Type::Float:
-      return os << value.Value<float>();
-  }
-  permanent_fail("Unsupported TypedValue::Type");
-}
-
-TypedValue& TypedValue::operator=(TypedValue&& other) {
-  // set the type of this
-  const_cast<Type&>(type_) = other.type_;
-
-  if (this != &other) {
-    switch (other.type_) {
-      case TypedValue::Type::Null:
-      case TypedValue::Type::Bool:
-        this->bool_v = other.bool_v;
-        return *this;
-      case TypedValue::Type::String:
-        this->string_v = std::move(other.string_v);
-        return *this;
-      case TypedValue::Type::Int:
-        this->int_v = other.int_v;
-        return *this;
-      case TypedValue::Type::Float:
-        this->float_v = other.float_v;
-        return *this;
-    }
-  }
-  permanent_fail("Unsupported TypedValue::Type");
-}
-
-const TypedValue TypedValue::Null = TypedValue();
-
-TypedValue::~TypedValue() {
-  switch (type_) {
-    // destructor for primitive types does nothing
-    case Type::Null:
-    case Type::Bool:
-    case Type::Int:
-    case Type::Float:
-      return;
-
-    // destructor for shared pointer must release
-    case Type::String:
-      string_v.~shared_ptr<std::string>();
-      return;
-  }
-  permanent_fail("Unsupported TypedValue::Type");
-}
-
-/**
- * Returns the float value of a value.
- * The value MUST be either Float or Int.
- *
- * @param value
- * @return
- */
-float ToFloat(const TypedValue& value) {
-  switch (value.type_) {
-    case TypedValue::Type::Int:
-      return (float)value.Value<int>();
-    case TypedValue::Type::Float:
-      return value.Value<float>();
-
-    default:
-      permanent_fail("Unsupported TypedValue::Type");
-  }
-}
-
-TypedValue operator<(const TypedValue& a, const TypedValue& b) {
-  if (a.type_ == TypedValue::Type::Bool || b.type_ == TypedValue::Type::Bool)
-    throw TypedValueException("Invalid 'less' operand types({} + {})", a.type_,
-                              b.type_);
-
-  if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
-    return TypedValue::Null;
-
-  if (a.type_ == TypedValue::Type::String ||
-      b.type_ == TypedValue::Type::String) {
-    if (a.type_ != b.type_)
-      throw TypedValueException("Invalid equality operand types({} + {})",
-                                a.type_, b.type_);
-    else
-      return a.Value<std::string>() < b.Value<std::string>();
-  }
-
-  // at this point we only have int and float
-  if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float)
-    return ToFloat(a) < ToFloat(b);
-  else
-    return a.Value<int>() < b.Value<int>();
-}
-
-TypedValue operator==(const TypedValue& a, const TypedValue& b) {
-  if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
-    return TypedValue::Null;
-
-  if (a.type_ == TypedValue::Type::String ||
-      b.type_ == TypedValue::Type::String) {
-    if (a.type_ != b.type_)
-      throw TypedValueException("Invalid equality operand types({} + {})",
-                                a.type_, b.type_);
-    else
-      return a.Value<std::string>() == b.Value<std::string>();
-  }
-
-  if (a.type_ == TypedValue::Type::Bool || b.type_ == TypedValue::Type::Bool) {
-    if (a.type_ != b.type_)
-      throw TypedValueException("Invalid equality operand types({} + {})",
-                                a.type_, b.type_);
-    else
-      return a.Value<bool>() == b.Value<bool>();
-  }
-  // at this point we only have int and float
-  if (a.type_ == TypedValue::Type::Float ||
-      b.type_ == TypedValue::Type::Float) {
-    return ToFloat(a) == ToFloat(b);
-  } else
-    return a.Value<int>() == b.Value<int>();
-}
-
-TypedValue operator!(const TypedValue& a) {
-  switch (a.type_) {
-    case TypedValue::Type::Null:
-      return TypedValue::Null;
-    case TypedValue::Type::Bool:
-      return TypedValue(!a.Value<bool>());
-
-    default:
-      throw TypedValueException("Invalid logical not operand type (!{})",
-                                a.type_);
-  }
-}
-
-/**
- * Turns a numeric or string value into a string.
- *
- * @param value a value.
- * @return A string.
- */
-std::string ValueToString(const TypedValue& value) {
-  switch (value.type_) {
-    case TypedValue::Type::String:
-      return value.Value<std::string>();
-    case TypedValue::Type::Int:
-      return std::to_string(value.Value<int>());
-    case TypedValue::Type::Float:
-      return fmt::format("{}", value.Value<float>());
-
-    // unsupported situations
-    default:
-      permanent_fail("Unsupported TypedValue::Type");
-  }
-}
-
-TypedValue operator-(const TypedValue& a) {
-  switch (a.type_) {
-    case TypedValue::Type::Null:
-      return TypedValue::Null;
-    case TypedValue::Type::Int:
-      return -a.Value<int>();
-    case TypedValue::Type::Float:
-      return -a.Value<float>();
-
-    default:
-      throw TypedValueException("Invalid unary minus operand type (-{})",
-                                a.type_);
-  }
-}
-
-/**
- * Raises a TypedValueException if the given values do not support arithmetic
- * operations. If they do, nothing happens.
- *
- * @param a First value.
- * @param b Second value.
- * @param string_ok If or not for the given operation it's valid to work with
- *  String values (typically it's OK only for sum).
- *  @param op_name Name of the operation, used only for exception description,
- *  if raised.
- */
-inline void EnsureArithmeticallyOk(const TypedValue& a, const TypedValue& b,
-                                   bool string_ok, const std::string& op_name) {
-  if (a.type_ == TypedValue::Type::Bool || b.type_ == TypedValue::Type::Bool)
-    throw TypedValueException("Invalid {} operand types {}, {}", op_name,
-                              a.type_, b.type_);
-
-  if (string_ok) return;
-
-  if (a.type_ == TypedValue::Type::String ||
-      b.type_ == TypedValue::Type::String)
-    throw TypedValueException("Invalid subtraction operands types {}, {}",
-                              a.type_, b.type_);
-}
-
-TypedValue operator+(const TypedValue& a, const TypedValue& b) {
-  EnsureArithmeticallyOk(a, b, true, "addition");
-  if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
-    return TypedValue::Null;
-
-  // no more Bool nor Null, summing works on anything from here onward
-
-  if (a.type_ == TypedValue::Type::String ||
-      b.type_ == TypedValue::Type::String)
-    return ValueToString(a) + ValueToString(b);
-
-  // at this point we only have int and float
-  if (a.type_ == TypedValue::Type::Float ||
-      b.type_ == TypedValue::Type::Float) {
-    return ToFloat(a) + ToFloat(b);
-  } else
-    return a.Value<int>() + b.Value<int>();
-}
-
-TypedValue operator-(const TypedValue& a, const TypedValue& b) {
-  EnsureArithmeticallyOk(a, b, false, "subtraction");
-
-  if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
-    return TypedValue::Null;
-
-  // at this point we only have int and float
-  if (a.type_ == TypedValue::Type::Float ||
-      b.type_ == TypedValue::Type::Float) {
-    return ToFloat(a) - ToFloat(b);
-  } else
-    return a.Value<int>() - b.Value<int>();
-}
-
-TypedValue operator/(const TypedValue& a, const TypedValue& b) {
-  EnsureArithmeticallyOk(a, b, false, "division");
-
-  if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
-    return TypedValue::Null;
-
-  // at this point we only have int and float
-  if (a.type_ == TypedValue::Type::Float ||
-      b.type_ == TypedValue::Type::Float) {
-    return ToFloat(a) / ToFloat(b);
-  } else
-    return a.Value<int>() / b.Value<int>();
-}
-
-TypedValue operator*(const TypedValue& a, const TypedValue& b) {
-  EnsureArithmeticallyOk(a, b, false, "multiplication");
-
-  if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
-    return TypedValue::Null;
-
-  // at this point we only have int and float
-  if (a.type_ == TypedValue::Type::Float ||
-      b.type_ == TypedValue::Type::Float) {
-    return ToFloat(a) * ToFloat(b);
-  } else
-    return a.Value<int>() * b.Value<int>();
-}
-
-TypedValue operator%(const TypedValue& a, const TypedValue& b) {
-  EnsureArithmeticallyOk(a, b, false, "modulo");
-
-  if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
-    return TypedValue::Null;
-
-  // at this point we only have int and float
-  if (a.type_ == TypedValue::Type::Float ||
-      b.type_ == TypedValue::Type::Float) {
-    return (float)fmod(ToFloat(a), ToFloat(b));
-  } else
-    return a.Value<int>() % b.Value<int>();
-}
-
-inline bool IsLogicallyOk(const TypedValue& a) {
-  return a.type_ == TypedValue::Type::Bool || a.type_ == TypedValue::Type::Null;
-}
-
-TypedValue operator&&(const TypedValue& a, const TypedValue& b) {
-  if (IsLogicallyOk(a) && IsLogicallyOk(b)) {
-    if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
-      return TypedValue::Null;
-    else
-      return a.Value<bool>() && b.Value<bool>();
-  } else
-    throw TypedValueException("Invalid logical and operand types({} && {})",
-                              a.type_, b.type_);
-}
-
-TypedValue operator||(const TypedValue& a, const TypedValue& b) {
-  if (IsLogicallyOk(a) && IsLogicallyOk(b)) {
-    if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null)
-      return TypedValue::Null;
-    else
-      return a.Value<bool>() || b.Value<bool>();
-  } else
-    throw TypedValueException("Invalid logical and operand types({} && {})",
-                              a.type_, b.type_);
-}
diff --git a/src/storage/vertex.hpp b/src/storage/vertex.hpp
index 2c09898e0..f8a39cc39 100644
--- a/src/storage/vertex.hpp
+++ b/src/storage/vertex.hpp
@@ -5,7 +5,7 @@
 #include "database/graph_db.hpp"
 #include "mvcc/record.hpp"
 #include "mvcc/version_list.hpp"
-#include "storage/typed_value_store.hpp"
+#include "storage/property_value_store.hpp"
 
 // forward declare Edge because there is a circular usage Edge <-> Vertex
 class Edge;
@@ -15,5 +15,5 @@ class Vertex : public mvcc::Record<Vertex> {
   std::vector<mvcc::VersionList<Edge>*> out_;
   std::vector<mvcc::VersionList<Edge>*> in_;
   std::vector<GraphDb::Label> labels_;
-  TypedValueStore<GraphDb::Property> properties_;
+  PropertyValueStore<GraphDb::Property> properties_;
 };
diff --git a/tests/integration/hardcoded_query/clique.cpp b/tests/integration/hardcoded_query/clique.cpp
index 39b20f740..1fa891261 100644
--- a/tests/integration/hardcoded_query/clique.cpp
+++ b/tests/integration/hardcoded_query/clique.cpp
@@ -20,7 +20,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     return run_general_query(db_accessor, args, stream, CliqueQuery::FIND_ALL);
   }
diff --git a/tests/integration/hardcoded_query/clique.hpp b/tests/integration/hardcoded_query/clique.hpp
index a5c8d8314..5551c52aa 100644
--- a/tests/integration/hardcoded_query/clique.hpp
+++ b/tests/integration/hardcoded_query/clique.hpp
@@ -3,6 +3,7 @@
 #include <iostream>
 #include <string>
 
+#include "query/backend/cpp/typed_value.hpp"
 #include "query/plan_interface.hpp"
 #include "storage/edge_accessor.hpp"
 #include "storage/vertex_accessor.hpp"
@@ -115,7 +116,7 @@ class Bitset {
 enum CliqueQuery { SCORE_AND_LIMIT, FIND_ALL };
 
 bool run_general_query(GraphDbAccessor &db_accessor,
-                       const TypedValueStore<> &args, Stream &stream,
+                       const PropertyValueStore<> &args, Stream &stream,
                        enum CliqueQuery query_type) {
   if (query_type == CliqueQuery::FIND_ALL)
     stream.write_fields(
@@ -137,11 +138,11 @@ bool run_general_query(GraphDbAccessor &db_accessor,
         vertices[i].has_label(db_accessor.label("profile"))) {
       auto has_prop =
           vertices[i].PropsAt(db_accessor.property("profile_id")) == args.at(0);
-      if (has_prop.type_ == TypedValue::Type::Null) continue;
+      if (has_prop.type() == TypedValue::Type::Null) continue;
       if (has_prop.Value<bool>() == false) continue;
       has_prop =
           vertices[i].PropsAt(db_accessor.property("partner_id")) == args.at(1);
-      if (has_prop.type_ == TypedValue::Type::Null) continue;
+      if (has_prop.type() == TypedValue::Type::Null) continue;
       if (has_prop.Value<bool>() == false) continue;
       profile_index = i;
     }
@@ -152,8 +153,8 @@ bool run_general_query(GraphDbAccessor &db_accessor,
       edges_indexed.push_back(&edges[i]);
   }
   const int n = vertices_indexed.size();
-  auto cmp_vertex = [](const VertexAccessor *a,
-                       const VertexAccessor *b) -> bool { return *a < *b; };
+  auto cmp_vertex = [](const VertexAccessor *a, const VertexAccessor *b)
+                        -> bool { return *a < *b; };
   auto cmp_edge = [](const EdgeAccessor *a, const EdgeAccessor *b) -> bool {
     if (a->from() != b->from()) return a->from() < b->from();
     return a->to() < b->to();
@@ -163,15 +164,15 @@ bool run_general_query(GraphDbAccessor &db_accessor,
    * @param v VertexAccessor to a vertex.
    * @return position of vertex or -1 if it doesn't exist.
    */
-  auto query = [&vertices_indexed,
-                &cmp_vertex](const VertexAccessor &v) -> int {
-    int pos = lower_bound(vertices_indexed.begin(), vertices_indexed.end(), &v,
-                          cmp_vertex) -
-              vertices_indexed.begin();
-    if (pos == (int)vertices_indexed.size() || *vertices_indexed[pos] != v)
-      return -1;
-    return pos;
-  };
+  auto query =
+      [&vertices_indexed, &cmp_vertex](const VertexAccessor &v) -> int {
+        int pos = lower_bound(vertices_indexed.begin(), vertices_indexed.end(),
+                              &v, cmp_vertex) -
+                  vertices_indexed.begin();
+        if (pos == (int)vertices_indexed.size() || *vertices_indexed[pos] != v)
+          return -1;
+        return pos;
+      };
   /**
    * Update bitset of neighbours. Set bit to 1 for index of every vertex
    * endpoint of edges with type default_outfit.
@@ -203,7 +204,7 @@ bool run_general_query(GraphDbAccessor &db_accessor,
     const VertexAccessor v = *vertices_indexed[i];
     auto cmp_res = v.PropsAt(db_accessor.property("garment_id")) ==
                    args.at(query_type == CliqueQuery::SCORE_AND_LIMIT ? 8 : 0);
-    if (cmp_res.type_ != TypedValue::Type::Bool) continue;
+    if (cmp_res.type() != TypedValue::Type::Bool) continue;
     if (cmp_res.Value<bool>() != true) continue;
     auto neigh = connected[i].Ones();
     for (int j : neigh) {
@@ -229,15 +230,16 @@ bool run_general_query(GraphDbAccessor &db_accessor,
    * @return EdgeAccessor* if it exists, nullptr otherwise.
    */
   auto get_edge = [&edges_indexed](
-      const VertexAccessor &first,
-      const VertexAccessor &second) -> EdgeAccessor * {
-    auto cmp_edge_to_pair = [](
-        const EdgeAccessor *edge,
-        const pair<const VertexAccessor *, const VertexAccessor *> &e) -> bool {
-      if (edge->from() != *e.first) return edge->from() < *e.first;
-      if (edge->to() != *e.second) return edge->to() < *e.second;
-      return false;
-    };
+                      const VertexAccessor &first,
+                      const VertexAccessor &second) -> EdgeAccessor *{
+    auto cmp_edge_to_pair =
+        [](const EdgeAccessor *edge,
+           const pair<const VertexAccessor *, const VertexAccessor *> &e)
+            -> bool {
+              if (edge->from() != *e.first) return edge->from() < *e.first;
+              if (edge->to() != *e.second) return edge->to() < *e.second;
+              return false;
+            };
     auto pos = lower_bound(edges_indexed.begin(), edges_indexed.end(),
                            std::make_pair(&first, &second), cmp_edge_to_pair) -
                edges_indexed.begin();
@@ -261,18 +263,19 @@ bool run_general_query(GraphDbAccessor &db_accessor,
    * @param V index of clique vertices in vertices_indexed.
    * @return score if profile_index exists, else 0.
    */
-  auto calc_score = [&db_accessor, &vertices, &profile_index, &vertices_indexed,
-                     &get_edge](const std::vector<int> &V) -> int {
-    int res = 0;
-    if (profile_index == -1) return 0;
-    for (auto x : V) {
-      auto edge = get_edge(vertices[profile_index], *vertices_indexed[x]);
-      if (edge == nullptr) continue;
-      auto prop = edge->PropsAt(db_accessor.property("score"));
-      if (prop.type_ == TypedValue::Type::Int) res += prop.Value<int>();
-    }
-    return res;
-  };
+  auto calc_score =
+      [&db_accessor, &vertices, &profile_index, &vertices_indexed, &get_edge](
+          const std::vector<int> &V) -> int {
+        int res = 0;
+        if (profile_index == -1) return 0;
+        for (auto x : V) {
+          auto edge = get_edge(vertices[profile_index], *vertices_indexed[x]);
+          if (edge == nullptr) continue;
+          auto prop = TypedValue(edge->PropsAt(db_accessor.property("score")));
+          if (prop.type() == TypedValue::Type::Int) res += prop.Value<int>();
+        }
+        return res;
+      };
   if (query_type == CliqueQuery::SCORE_AND_LIMIT) {
     auto cmp_results = [&calc_score](const std::vector<int> &first,
                                      const std::vector<int> &second) {
diff --git a/tests/integration/hardcoded_query/clique_scored.cpp b/tests/integration/hardcoded_query/clique_scored.cpp
index c091f7a01..cb8367dff 100644
--- a/tests/integration/hardcoded_query/clique_scored.cpp
+++ b/tests/integration/hardcoded_query/clique_scored.cpp
@@ -26,7 +26,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     return run_general_query(db_accessor, args, stream,
                              CliqueQuery::SCORE_AND_LIMIT);
diff --git a/tests/integration/hardcoded_query/create_full_profile_conceals_return.cpp b/tests/integration/hardcoded_query/create_full_profile_conceals_return.cpp
index 7b7097498..3b35f8892 100644
--- a/tests/integration/hardcoded_query/create_full_profile_conceals_return.cpp
+++ b/tests/integration/hardcoded_query/create_full_profile_conceals_return.cpp
@@ -14,7 +14,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     auto v = db_accessor.insert_vertex();
     v.PropsSet(db_accessor.property("profile_id"), args.at(0));
diff --git a/tests/integration/hardcoded_query/create_full_profile_return.cpp b/tests/integration/hardcoded_query/create_full_profile_return.cpp
index de025c2c4..c40d6371a 100644
--- a/tests/integration/hardcoded_query/create_full_profile_return.cpp
+++ b/tests/integration/hardcoded_query/create_full_profile_return.cpp
@@ -13,7 +13,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     auto v = db_accessor.insert_vertex();
     v.PropsSet(db_accessor.property("profile_id"), args.at(0));
diff --git a/tests/integration/hardcoded_query/create_full_profile_reveals_return.cpp b/tests/integration/hardcoded_query/create_full_profile_reveals_return.cpp
index 5c120a0ff..1b10d3128 100644
--- a/tests/integration/hardcoded_query/create_full_profile_reveals_return.cpp
+++ b/tests/integration/hardcoded_query/create_full_profile_reveals_return.cpp
@@ -14,7 +14,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     auto v = db_accessor.insert_vertex();
     v.PropsSet(db_accessor.property("profile_id"), args.at(0));
diff --git a/tests/integration/hardcoded_query/create_garment.cpp b/tests/integration/hardcoded_query/create_garment.cpp
index 354f78e77..004724e54 100644
--- a/tests/integration/hardcoded_query/create_garment.cpp
+++ b/tests/integration/hardcoded_query/create_garment.cpp
@@ -13,7 +13,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     auto v = db_accessor.insert_vertex();
     v.add_label(db_accessor.label("garment"));
diff --git a/tests/integration/hardcoded_query/create_garment_conceals.cpp b/tests/integration/hardcoded_query/create_garment_conceals.cpp
index b8d02fe4e..0cfaea0c1 100644
--- a/tests/integration/hardcoded_query/create_garment_conceals.cpp
+++ b/tests/integration/hardcoded_query/create_garment_conceals.cpp
@@ -14,7 +14,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     auto v = db_accessor.insert_vertex();
     v.add_label(db_accessor.label("garment"));
diff --git a/tests/integration/hardcoded_query/create_garment_reveals.cpp b/tests/integration/hardcoded_query/create_garment_reveals.cpp
index 74c072278..50762b5ab 100644
--- a/tests/integration/hardcoded_query/create_garment_reveals.cpp
+++ b/tests/integration/hardcoded_query/create_garment_reveals.cpp
@@ -14,7 +14,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     auto v = db_accessor.insert_vertex();
     v.add_label(db_accessor.label("garment"));
diff --git a/tests/integration/hardcoded_query/delete_all.cpp b/tests/integration/hardcoded_query/delete_all.cpp
index 5af43f6f6..83083059e 100644
--- a/tests/integration/hardcoded_query/delete_all.cpp
+++ b/tests/integration/hardcoded_query/delete_all.cpp
@@ -11,7 +11,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     for (auto v : db_accessor.vertices()) db_accessor.detach_remove_vertex(v);
     stream.write_empty_fields();
diff --git a/tests/integration/hardcoded_query/match_garment.cpp b/tests/integration/hardcoded_query/match_garment.cpp
index 42b4786e2..4094f94aa 100644
--- a/tests/integration/hardcoded_query/match_garment.cpp
+++ b/tests/integration/hardcoded_query/match_garment.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <string>
 
+#include "query/backend/cpp/typed_value.hpp"
 #include "query/plan_interface.hpp"
 #include "storage/edge_accessor.hpp"
 #include "storage/vertex_accessor.hpp"
@@ -13,15 +14,15 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     stream.write_field("g");
     for (auto vertex : db_accessor.vertices()) {
       if (vertex.has_label(db_accessor.label("garment"))) {
-        auto prop = vertex.PropsAt(db_accessor.property("garment_id"));
-        if (prop.type_ == TypedValue::Type::Null) continue;
+        TypedValue prop = vertex.PropsAt(db_accessor.property("garment_id"));
+        if (prop.type() == TypedValue::Type::Null) continue;
         auto cmp = prop == args.at(0);
-        if (cmp.type_ != TypedValue::Type::Bool) continue;
+        if (cmp.type() != TypedValue::Type::Bool) continue;
         if (cmp.Value<bool>() != true) continue;
         stream.write_vertex_record(vertex);
       }
diff --git a/tests/integration/hardcoded_query/match_garment_default_outfit.cpp b/tests/integration/hardcoded_query/match_garment_default_outfit.cpp
index 640d4550e..ef9bf1fd2 100644
--- a/tests/integration/hardcoded_query/match_garment_default_outfit.cpp
+++ b/tests/integration/hardcoded_query/match_garment_default_outfit.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <string>
 
+#include "query/backend/cpp/typed_value.hpp"
 #include "query/plan_interface.hpp"
 #include "storage/edge_accessor.hpp"
 #include "storage/vertex_accessor.hpp"
@@ -14,16 +15,16 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     stream.write_field("r");
     std::vector<VertexAccessor> g1_set, g2_set;
     for (auto g1 : db_accessor.vertices()) {
       if (g1.has_label(db_accessor.label("garment"))) {
-        auto prop = g1.PropsAt(db_accessor.property("garment_id"));
-        if (prop.type_ == TypedValue::Type::Null) continue;
+        TypedValue prop = g1.PropsAt(db_accessor.property("garment_id"));
+        if (prop.type() == TypedValue::Type::Null) continue;
         auto cmp = prop == args.at(0);
-        if (cmp.type_ != TypedValue::Type::Bool) continue;
+        if (cmp.type() != TypedValue::Type::Bool) continue;
         if (cmp.Value<bool>() != true) continue;
         g1_set.push_back(g1);
       }
@@ -31,9 +32,9 @@ class CPUPlan : public PlanInterface<Stream> {
     for (auto g2 : db_accessor.vertices()) {
       if (g2.has_label(db_accessor.label("garment"))) {
         auto prop = g2.PropsAt(db_accessor.property("garment_id"));
-        if (prop.type_ == TypedValue::Type::Null) continue;
+        if (prop.type() == PropertyValue::Type::Null) continue;
         auto cmp = prop == args.at(1);
-        if (cmp.type_ != TypedValue::Type::Bool) continue;
+        if (cmp.type() != TypedValue::Type::Bool) continue;
         if (cmp.Value<bool>() != true) continue;
         g2_set.push_back(g2);
       }
diff --git a/tests/integration/hardcoded_query/match_garment_set_label_AA_return.cpp b/tests/integration/hardcoded_query/match_garment_set_label_AA_return.cpp
index a487c944f..01e3cc748 100644
--- a/tests/integration/hardcoded_query/match_garment_set_label_AA_return.cpp
+++ b/tests/integration/hardcoded_query/match_garment_set_label_AA_return.cpp
@@ -12,7 +12,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     return run_general_query(db_accessor, args, stream, "AA");
   }
diff --git a/tests/integration/hardcoded_query/match_garment_set_label_BB_return.cpp b/tests/integration/hardcoded_query/match_garment_set_label_BB_return.cpp
index 1f320565a..94505f5ec 100644
--- a/tests/integration/hardcoded_query/match_garment_set_label_BB_return.cpp
+++ b/tests/integration/hardcoded_query/match_garment_set_label_BB_return.cpp
@@ -12,7 +12,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     return run_general_query(db_accessor, args, stream, "BB");
   }
diff --git a/tests/integration/hardcoded_query/match_garment_set_label_CC_return.cpp b/tests/integration/hardcoded_query/match_garment_set_label_CC_return.cpp
index e167fa18b..67f2c895f 100644
--- a/tests/integration/hardcoded_query/match_garment_set_label_CC_return.cpp
+++ b/tests/integration/hardcoded_query/match_garment_set_label_CC_return.cpp
@@ -12,7 +12,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     return run_general_query(db_accessor, args, stream, "CC");
   }
diff --git a/tests/integration/hardcoded_query/match_garment_set_label_DD_return.cpp b/tests/integration/hardcoded_query/match_garment_set_label_DD_return.cpp
index c3f54971a..da9ee716e 100644
--- a/tests/integration/hardcoded_query/match_garment_set_label_DD_return.cpp
+++ b/tests/integration/hardcoded_query/match_garment_set_label_DD_return.cpp
@@ -12,7 +12,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     return run_general_query(db_accessor, args, stream, "DD");
   }
diff --git a/tests/integration/hardcoded_query/match_garment_set_label_EE_return.cpp b/tests/integration/hardcoded_query/match_garment_set_label_EE_return.cpp
index 627ff9628..c394160c1 100644
--- a/tests/integration/hardcoded_query/match_garment_set_label_EE_return.cpp
+++ b/tests/integration/hardcoded_query/match_garment_set_label_EE_return.cpp
@@ -12,7 +12,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     return run_general_query(db_accessor, args, stream, "EE");
   }
diff --git a/tests/integration/hardcoded_query/match_garment_set_label_general_return.hpp b/tests/integration/hardcoded_query/match_garment_set_label_general_return.hpp
index d0f5f1b15..9b7de1006 100644
--- a/tests/integration/hardcoded_query/match_garment_set_label_general_return.hpp
+++ b/tests/integration/hardcoded_query/match_garment_set_label_general_return.hpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <string>
 
+#include "query/backend/cpp/typed_value.hpp"
 #include "query/plan_interface.hpp"
 #include "storage/edge_accessor.hpp"
 #include "storage/vertex_accessor.hpp"
@@ -13,15 +14,15 @@ using std::endl;
 // RETURN g
 
 bool run_general_query(GraphDbAccessor &db_accessor,
-                       const TypedValueStore<> &args, Stream &stream,
+                       const PropertyValueStore<> &args, Stream &stream,
                        const std::string &general_label) {
   stream.write_field("g");
   for (auto vertex : db_accessor.vertices()) {
     if (vertex.has_label(db_accessor.label("garment"))) {
-      auto prop = vertex.PropsAt(db_accessor.property("garment_id"));
-      if (prop.type_ == TypedValue::Type::Null) continue;
-      auto cmp = prop == args.at(0);
-      if (cmp.type_ != TypedValue::Type::Bool) continue;
+      TypedValue prop = vertex.PropsAt(db_accessor.property("garment_id"));
+      if (prop.type() == TypedValue::Type::Null) continue;
+      TypedValue cmp = prop == args.at(0);
+      if (cmp.type() != TypedValue::Type::Bool) continue;
       if (cmp.Value<bool>() != true) continue;
       vertex.add_label(db_accessor.label(general_label));
       stream.write_vertex_record(vertex);
diff --git a/tests/integration/hardcoded_query/match_profile.cpp b/tests/integration/hardcoded_query/match_profile.cpp
index 0cb626bb4..da9d6b152 100644
--- a/tests/integration/hardcoded_query/match_profile.cpp
+++ b/tests/integration/hardcoded_query/match_profile.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <string>
 
+#include "query/backend/cpp/typed_value.hpp"
 #include "query/plan_interface.hpp"
 #include "storage/edge_accessor.hpp"
 #include "storage/vertex_accessor.hpp"
@@ -13,21 +14,21 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     stream.write_field("p");
     for (auto vertex : db_accessor.vertices()) {
       if (vertex.has_label(db_accessor.label("profile"))) {
-        auto prop = vertex.PropsAt(db_accessor.property("profile_id"));
-        if (prop.type_ == TypedValue::Type::Null) continue;
+        TypedValue prop = vertex.PropsAt(db_accessor.property("profile_id"));
+        if (prop.type() == TypedValue::Type::Null) continue;
         auto cmp = prop == args.at(0);
-        if (cmp.type_ != TypedValue::Type::Bool) continue;
+        if (cmp.type() != TypedValue::Type::Bool) continue;
         if (cmp.Value<bool>() != true) continue;
 
-        auto prop2 = vertex.PropsAt(db_accessor.property("partner_id"));
-        if (prop2.type_ == TypedValue::Type::Null) continue;
+        TypedValue prop2 = vertex.PropsAt(db_accessor.property("partner_id"));
+        if (prop2.type() == TypedValue::Type::Null) continue;
         auto cmp2 = prop2 == args.at(1);
-        if (cmp2.type_ != TypedValue::Type::Bool) continue;
+        if (cmp2.type() != TypedValue::Type::Bool) continue;
         if (cmp2.Value<bool>() != true) continue;
         stream.write_vertex_record(vertex);
       }
diff --git a/tests/integration/hardcoded_query/match_profile_garment_score.cpp b/tests/integration/hardcoded_query/match_profile_garment_score.cpp
index 95845bef8..6752ddbf8 100644
--- a/tests/integration/hardcoded_query/match_profile_garment_score.cpp
+++ b/tests/integration/hardcoded_query/match_profile_garment_score.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <string>
 
+#include "query/backend/cpp/typed_value.hpp"
 #include "query/plan_interface.hpp"
 #include "storage/edge_accessor.hpp"
 #include "storage/vertex_accessor.hpp"
@@ -15,27 +16,27 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     stream.write_field("s");
     auto profile = [&db_accessor, &args](const VertexAccessor &v) -> bool {
-      auto prop = v.PropsAt(db_accessor.property("profile_id"));
-      if (prop.type_ == TypedValue::Type::Null) return false;
+      TypedValue prop = v.PropsAt(db_accessor.property("profile_id"));
+      if (prop.type() == TypedValue::Type::Null) return false;
       auto cmp = prop == args.at(0);
-      if (cmp.type_ != TypedValue::Type::Bool) return false;
+      if (cmp.type() != TypedValue::Type::Bool) return false;
       if (cmp.Value<bool>() != true) return false;
 
-      auto prop2 = v.PropsAt(db_accessor.property("partner_id"));
-      if (prop2.type_ == TypedValue::Type::Null) return false;
+      TypedValue prop2 = v.PropsAt(db_accessor.property("partner_id"));
+      if (prop2.type() == TypedValue::Type::Null) return false;
       auto cmp2 = prop2 == args.at(1);
-      if (cmp2.type_ != TypedValue::Type::Bool) return false;
+      if (cmp2.type() != TypedValue::Type::Bool) return false;
       return cmp2.Value<bool>();
     };
     auto garment = [&db_accessor, &args](const VertexAccessor &v) -> bool {
-      auto prop = v.PropsAt(db_accessor.property("garment_id"));
-      if (prop.type_ == TypedValue::Type::Null) return false;
+      TypedValue prop = v.PropsAt(db_accessor.property("garment_id"));
+      if (prop.type() == TypedValue::Type::Null) return false;
       auto cmp = prop == args.at(2);
-      if (cmp.type_ != TypedValue::Type::Bool) return false;
+      if (cmp.type() != TypedValue::Type::Bool) return false;
       return cmp.Value<bool>();
     };
     for (auto edge : db_accessor.edges()) {
diff --git a/tests/integration/hardcoded_query/match_profile_garment_set_score.cpp b/tests/integration/hardcoded_query/match_profile_garment_set_score.cpp
index 4c65b268b..49142278a 100644
--- a/tests/integration/hardcoded_query/match_profile_garment_set_score.cpp
+++ b/tests/integration/hardcoded_query/match_profile_garment_set_score.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <string>
 
+#include "query/backend/cpp/typed_value.hpp"
 #include "query/plan_interface.hpp"
 #include "storage/edge_accessor.hpp"
 #include "storage/vertex_accessor.hpp"
@@ -14,32 +15,32 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     stream.write_field("r");
     std::vector<VertexAccessor> g1_set, g2_set;
     for (auto g1 : db_accessor.vertices()) {
       if (g1.has_label(db_accessor.label("profile"))) {
-        auto prop = g1.PropsAt(db_accessor.property("profile_id"));
-        if (prop.type_ == TypedValue::Type::Null) continue;
+        auto prop = TypedValue(g1.PropsAt(db_accessor.property("profile_id")));
+        if (prop.type() == TypedValue::Type::Null) continue;
         auto cmp = prop == args.at(0);
-        if (cmp.type_ != TypedValue::Type::Bool) continue;
+        if (cmp.type() != TypedValue::Type::Bool) continue;
         if (cmp.Value<bool>() != true) continue;
 
-        auto prop2 = g1.PropsAt(db_accessor.property("partner_id"));
-        if (prop2.type_ == TypedValue::Type::Null) continue;
+        auto prop2 = TypedValue(g1.PropsAt(db_accessor.property("partner_id")));
+        if (prop2.type() == TypedValue::Type::Null) continue;
         auto cmp2 = prop2 == args.at(1);
-        if (cmp2.type_ != TypedValue::Type::Bool) continue;
+        if (cmp2.type() != TypedValue::Type::Bool) continue;
         if (cmp2.Value<bool>() != true) continue;
         g1_set.push_back(g1);
       }
     }
     for (auto g2 : db_accessor.vertices()) {
       if (g2.has_label(db_accessor.label("garment"))) {
-        auto prop = g2.PropsAt(db_accessor.property("garment_id"));
-        if (prop.type_ == TypedValue::Type::Null) continue;
+        auto prop = TypedValue(g2.PropsAt(db_accessor.property("garment_id")));
+        if (prop.type() == TypedValue::Type::Null) continue;
         auto cmp = prop == args.at(2);
-        if (cmp.type_ != TypedValue::Type::Bool) continue;
+        if (cmp.type() != TypedValue::Type::Bool) continue;
         if (cmp.Value<bool>() != true) continue;
         g2_set.push_back(g2);
       }
diff --git a/tests/integration/hardcoded_query/match_profile_garment_update_score.cpp b/tests/integration/hardcoded_query/match_profile_garment_update_score.cpp
index 180923d9c..e69f4c1cb 100644
--- a/tests/integration/hardcoded_query/match_profile_garment_update_score.cpp
+++ b/tests/integration/hardcoded_query/match_profile_garment_update_score.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <string>
 
+#include "query/backend/cpp/typed_value.hpp"
 #include "query/plan_interface.hpp"
 #include "storage/edge_accessor.hpp"
 #include "storage/vertex_accessor.hpp"
@@ -15,27 +16,27 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     stream.write_field("s");
     auto profile = [&db_accessor, &args](const VertexAccessor &v) -> bool {
-      auto prop = v.PropsAt(db_accessor.property("profile_id"));
-      if (prop.type_ == TypedValue::Type::Null) return false;
+      TypedValue prop = v.PropsAt(db_accessor.property("profile_id"));
+      if (prop.type() == TypedValue::Type::Null) return false;
       auto cmp = prop == args.at(0);
-      if (cmp.type_ != TypedValue::Type::Bool) return false;
+      if (cmp.type() != TypedValue::Type::Bool) return false;
       if (cmp.Value<bool>() != true) return false;
 
-      auto prop2 = v.PropsAt(db_accessor.property("partner_id"));
-      if (prop2.type_ == TypedValue::Type::Null) return false;
+      TypedValue prop2 = v.PropsAt(db_accessor.property("partner_id"));
+      if (prop2.type() == TypedValue::Type::Null) return false;
       auto cmp2 = prop2 == args.at(1);
-      if (cmp2.type_ != TypedValue::Type::Bool) return false;
+      if (cmp2.type() != TypedValue::Type::Bool) return false;
       return cmp2.Value<bool>();
     };
     auto garment = [&db_accessor, &args](const VertexAccessor &v) -> bool {
-      auto prop = v.PropsAt(db_accessor.property("garment_id"));
-      if (prop.type_ == TypedValue::Type::Null) return false;
+      TypedValue prop = v.PropsAt(db_accessor.property("garment_id"));
+      if (prop.type() == TypedValue::Type::Null) return false;
       auto cmp = prop == args.at(2);
-      if (cmp.type_ != TypedValue::Type::Bool) return false;
+      if (cmp.type() != TypedValue::Type::Bool) return false;
       return cmp.Value<bool>();
     };
     for (auto edge : db_accessor.edges()) {
diff --git a/tests/integration/hardcoded_query/template b/tests/integration/hardcoded_query/template
index 9d234b736..1afa3a043 100644
--- a/tests/integration/hardcoded_query/template
+++ b/tests/integration/hardcoded_query/template
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <string>
 
+#include "query/backend/cpp/typed_value.hpp"
 #include "query/plan_interface.hpp"
 #include "using.hpp"
 
@@ -11,7 +12,7 @@ using std::endl;
 
 class CPUPlan : public PlanInterface<Stream> {
  public:
-  bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args,
+  bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
            Stream &stream) {
     db_accessor.transaction_.commit();
     return true;
diff --git a/tests/integration/stream/print_record_stream.hpp b/tests/integration/stream/print_record_stream.hpp
index e05309b35..42d57e91e 100644
--- a/tests/integration/stream/print_record_stream.hpp
+++ b/tests/integration/stream/print_record_stream.hpp
@@ -5,11 +5,12 @@
 #include <string>
 #include <vector>
 
+#include "query/backend/cpp/typed_value.hpp"
 #include "storage/edge_accessor.hpp"
 #include "storage/vertex_accessor.hpp"
 
 void write_properties(std::ostream &os, const GraphDbAccessor &access,
-                      const TypedValueStore<GraphDb::Property> &properties) {
+                      const PropertyValueStore<GraphDb::Property> &properties) {
   if (properties.size() > 0) {
     os << "{";
     for (auto x : properties) {
diff --git a/tests/unit/property_value_store.cpp b/tests/unit/property_value_store.cpp
new file mode 100644
index 000000000..9ff51c91c
--- /dev/null
+++ b/tests/unit/property_value_store.cpp
@@ -0,0 +1,130 @@
+//
+// Copyright 2017 Memgraph
+// Created by Florijan Stamenkovic on 24.01.17..
+//
+#include <vector>
+
+#include "gtest/gtest.h"
+
+#include "storage/property_value_store.hpp"
+#include "storage/property_value.hpp"
+
+using std::string;
+
+TEST(PropertyValueStore, At) {
+  std::string some_string = "something";
+
+  PropertyValueStore<> props;
+  EXPECT_EQ(PropertyValue(props.at(0)).type(), PropertyValue::Type::Null);
+  props.set(0, some_string);
+  EXPECT_EQ(PropertyValue(props.at(0)).Value<string>(), some_string);
+  props.set(120, 42);
+  EXPECT_EQ(PropertyValue(props.at(120)).Value<int>(), 42);
+}
+
+TEST(PropertyValueStore, AtNull) {
+  PropertyValueStore<> props;
+  EXPECT_EQ(props.at(0).type(), PropertyValue::Type::Null);
+  EXPECT_EQ(props.at(100).type(), PropertyValue::Type::Null);
+
+  // set one prop and test it's not null
+  props.set(0, true);
+  EXPECT_NE(props.at(0).type(), PropertyValue::Type::Null);
+  EXPECT_EQ(props.at(100).type(), PropertyValue::Type::Null);
+}
+
+TEST(PropertyValueStore, Remove) {
+  // set some props
+  PropertyValueStore<> props;
+  props.set(11, "a");
+  props.set(30, "b");
+  EXPECT_NE(props.at(11).type(), PropertyValue::Type::Null);
+  EXPECT_NE(props.at(30).type(), PropertyValue::Type::Null);
+  EXPECT_EQ(props.size(), 2);
+
+  props.erase(11);
+  EXPECT_EQ(props.size(), 1);
+  EXPECT_EQ(props.at(11).type(), PropertyValue::Type::Null);
+
+  EXPECT_EQ(props.erase(30), 1);
+  EXPECT_EQ(props.size(), 0);
+  EXPECT_EQ(props.at(30).type(), PropertyValue::Type::Null);
+
+  EXPECT_EQ(props.erase(1000), 0);
+}
+
+TEST(PropertyValueStore, Replace) {
+  PropertyValueStore<> props;
+  props.set(10, 42);
+  EXPECT_EQ(props.at(10).Value<int>(), 42);
+  props.set(10, 0.25f);
+  EXPECT_EQ(props.at(10).type(), PropertyValue::Type::Double);
+  EXPECT_FLOAT_EQ(props.at(10).Value<double>(), 0.25);
+}
+
+TEST(PropertyValueStore, Size) {
+  PropertyValueStore<> props;
+  EXPECT_EQ(props.size(), 0);
+
+  props.set(0, "something");
+  EXPECT_EQ(props.size(), 1);
+  props.set(0, true);
+  EXPECT_EQ(props.size(), 1);
+  props.set(1, true);
+  EXPECT_EQ(props.size(), 2);
+
+  for (int i = 0; i < 100; ++i) props.set(i + 20, true);
+  EXPECT_EQ(props.size(), 102);
+
+  props.erase(0);
+  EXPECT_EQ(props.size(), 101);
+  props.erase(0);
+  EXPECT_EQ(props.size(), 101);
+  props.erase(1);
+  EXPECT_EQ(props.size(), 100);
+}
+
+TEST(PropertyValueStore, Accept) {
+  int count_props = 0;
+  int count_finish = 0;
+
+  auto handler =
+      [&](const uint32_t, const PropertyValue&) { count_props += 1; };
+  auto finish = [&]() { count_finish += 1; };
+
+  PropertyValueStore<uint32_t> props;
+  props.Accept(handler, finish);
+  EXPECT_EQ(count_props, 0);
+  EXPECT_EQ(count_finish, 1);
+
+  props.Accept(handler);
+  EXPECT_EQ(count_props, 0);
+  EXPECT_EQ(count_finish, 1);
+
+  props.set(0, 20);
+  props.set(1, "bla");
+
+  props.Accept(handler, finish);
+  EXPECT_EQ(count_props, 2);
+  EXPECT_EQ(count_finish, 2);
+}
+
+TEST(PropertyValueStore, InsertRetrieveList) {
+  PropertyValueStore<> props;
+  props.set(0, std::vector<PropertyValue>{1, true, 2.5, "something",
+                                          PropertyValue::Null});
+  auto p = props.at(0);
+
+  EXPECT_EQ(p.type(), PropertyValue::Type::List);
+  auto l = p.Value<std::vector<PropertyValue>>();
+  EXPECT_EQ(l.size(), 5);
+  EXPECT_EQ(l[0].type(), PropertyValue::Type::Int);
+  EXPECT_EQ(l[0].Value<int>(), 1);
+  EXPECT_EQ(l[1].type(), PropertyValue::Type::Bool);
+  EXPECT_EQ(l[1].Value<bool>(), true);
+  EXPECT_EQ(l[2].type(), PropertyValue::Type::Double);
+  EXPECT_EQ(l[2].Value<double>(), 2.5);
+  EXPECT_EQ(l[3].type(), PropertyValue::Type::String);
+  EXPECT_EQ(l[3].Value<std::string>(), "something");
+  EXPECT_EQ(l[4].type(), PropertyValue::Type::Null);
+}
diff --git a/tests/unit/record_edge_vertex_accessor.cpp b/tests/unit/record_edge_vertex_accessor.cpp
index 1827aef58..7b455a22a 100644
--- a/tests/unit/record_edge_vertex_accessor.cpp
+++ b/tests/unit/record_edge_vertex_accessor.cpp
@@ -7,7 +7,7 @@
 #include "dbms/dbms.hpp"
 
 #include "storage/edge_accessor.hpp"
-#include "storage/typed_value.hpp"
+#include "storage/property_value.hpp"
 #include "storage/vertex_accessor.hpp"
 
 TEST(RecordAccessor, Properties) {
@@ -19,17 +19,17 @@ TEST(RecordAccessor, Properties) {
 
   auto property = dba.property("PropName");
   auto property_other = dba.property("Other");
-  EXPECT_EQ(vertex.PropsAt(property).type_, TypedValue::Type::Null);
+  EXPECT_EQ(vertex.PropsAt(property).type(), PropertyValue::Type::Null);
 
   vertex.PropsSet(property, 42);
   EXPECT_EQ(vertex.PropsAt(property).Value<int>(), 42);
   EXPECT_EQ(properties.at(property).Value<int>(), 42);
-  EXPECT_EQ(vertex.PropsAt(property_other).type_, TypedValue::Type::Null);
-  EXPECT_EQ(properties.at(property_other).type_, TypedValue::Type::Null);
+  EXPECT_EQ(vertex.PropsAt(property_other).type(), PropertyValue::Type::Null);
+  EXPECT_EQ(properties.at(property_other).type(), PropertyValue::Type::Null);
 
   vertex.PropsErase(property);
-  EXPECT_EQ(vertex.PropsAt(property).type_, TypedValue::Type::Null);
-  EXPECT_EQ(properties.at(property).type_, TypedValue::Type::Null);
+  EXPECT_EQ(vertex.PropsAt(property).type(), PropertyValue::Type::Null);
+  EXPECT_EQ(properties.at(property).type(), PropertyValue::Type::Null);
 }
 
 TEST(RecordAccessor, DbAccessor) {
diff --git a/tests/unit/record_stream_mocker.cpp b/tests/unit/record_stream_mocker.cpp
index 9e8b9b855..476d6a080 100644
--- a/tests/unit/record_stream_mocker.cpp
+++ b/tests/unit/record_stream_mocker.cpp
@@ -20,11 +20,11 @@ TEST(RecordStreamMocker, Headers) {
 TEST(RecordStreamMocker, OneValue) {
   bolt::RecordStreamMocker rs;
   rs.write_field("n");
-  rs.write(TypedValue(5));
+  rs.write(PropertyValue(5));
   ASSERT_EQ(rs.count_message_columns("fields"), 1);
   std::vector<antlrcpp::Any> output = rs.get_message_column("fields", 0);
   ASSERT_EQ(output.size(), 1);
-  auto val = output[0].as<TypedValue>().Value<int>();
+  auto val = output[0].as<PropertyValue>().Value<int>();
   ASSERT_EQ(val, 5);
 }
 
@@ -33,14 +33,14 @@ TEST(RecordStreamMocker, OneListOfInts) {
   rs.write_field("n");
   std::vector<int> expected_output = {5, 4, 6, 7};
   rs.write_list_header(expected_output.size());
-  for (auto x : expected_output) rs.write(TypedValue(x));
+  for (auto x : expected_output) rs.write(PropertyValue(x));
   ASSERT_EQ(rs.count_message_columns("fields"), 1);
   std::vector<antlrcpp::Any> output = rs.get_message_column("fields", 0);
   ASSERT_EQ(output.size(), 1);
   std::vector<antlrcpp::Any> list = output[0].as<std::vector<antlrcpp::Any>>();
   ASSERT_EQ(list.size(), expected_output.size());
   for (int i = 0; i < list.size(); ++i) {
-    auto val = list[i].as<TypedValue>().Value<int>();
+    auto val = list[i].as<PropertyValue>().Value<int>();
     ASSERT_EQ(val, expected_output[i]);
   }
 }
@@ -53,18 +53,18 @@ TEST(RecordStreamMocker, OneListOfIntAndList) {
   rs.write_list_header(2);
   rs.write(expected_value);
   rs.write_list_header(4);
-  for (auto x : expected_output) rs.write(TypedValue(x));
+  for (auto x : expected_output) rs.write(PropertyValue(x));
 
   ASSERT_EQ(rs.count_message_columns("fields"), 1);
   std::vector<antlrcpp::Any> output = rs.get_message_column("fields", 0);
   ASSERT_EQ(output.size(), 1);
   std::vector<antlrcpp::Any> list = output[0].as<std::vector<antlrcpp::Any>>();
   ASSERT_EQ(list.size(), 2);
-  ASSERT_EQ(list[0].as<TypedValue>().Value<int>(), expected_value);
+  ASSERT_EQ(list[0].as<PropertyValue>().Value<int>(), expected_value);
 
   auto list_inside = list[1].as<std::vector<antlrcpp::Any>>();
   for (int i = 0; i < list_inside.size(); ++i) {
-    auto val = list_inside[i].as<TypedValue>().Value<int>();
+    auto val = list_inside[i].as<PropertyValue>().Value<int>();
     ASSERT_EQ(val, expected_output[i]);
   }
 }
diff --git a/tests/unit/typed_value.cpp b/tests/unit/typed_value.cpp
index 5bb8a905b..495cbe29d 100644
--- a/tests/unit/typed_value.cpp
+++ b/tests/unit/typed_value.cpp
@@ -6,25 +6,23 @@
 #include <vector>
 
 #include "gtest/gtest.h"
+#include "query/backend/cpp/typed_value.hpp"
 
-#include "storage/typed_value.hpp"
-#include "storage/typed_value_store.hpp"
+namespace {
 
-TypedValueStore<> MakePropsAllTypes() {
-  TypedValueStore<> props;
-  props.set(0, true);
-  props.set(1, "something");
-  props.set(2, 42);
-  props.set(3, 0.5f);
-  return props;
+std::vector<TypedValue> MakePropsAllTypes() {
+  return {
+      true, "something", 42, 0.5, TypedValue::Null,
+      std::vector<TypedValue>{true, "something", 42, 0.5, TypedValue::Null}};
+}
 }
 
 void EXPECT_PROP_FALSE(const TypedValue& a) {
-  EXPECT_TRUE(a.type_ == TypedValue::Type::Bool && !a.Value<bool>());
+  EXPECT_TRUE(a.type() == TypedValue::Type::Bool && !a.Value<bool>());
 }
 
 void EXPECT_PROP_TRUE(const TypedValue& a) {
-  EXPECT_TRUE(a.type_ == TypedValue::Type::Bool && a.Value<bool>());
+  EXPECT_TRUE(a.type() == TypedValue::Type::Bool && a.Value<bool>());
 }
 
 void EXPECT_PROP_EQ(const TypedValue& a, const TypedValue& b) {
@@ -32,7 +30,7 @@ void EXPECT_PROP_EQ(const TypedValue& a, const TypedValue& b) {
 }
 
 void EXPECT_PROP_ISNULL(const TypedValue& a) {
-  EXPECT_TRUE(a.type_ == TypedValue::Type::Null);
+  EXPECT_TRUE(a.type() == TypedValue::Type::Null);
 }
 
 void EXPECT_PROP_NE(const TypedValue& a, const TypedValue& b) {
@@ -40,20 +38,20 @@ void EXPECT_PROP_NE(const TypedValue& a, const TypedValue& b) {
 }
 
 TEST(TypedValue, CreationTypes) {
-  EXPECT_TRUE(TypedValue::Null.type_ == TypedValue::Type::Null);
+  EXPECT_TRUE(TypedValue::Null.type() == TypedValue::Type::Null);
 
-  EXPECT_TRUE(TypedValue(true).type_ == TypedValue::Type::Bool);
-  EXPECT_TRUE(TypedValue(false).type_ == TypedValue::Type::Bool);
+  EXPECT_TRUE(TypedValue(true).type() == TypedValue::Type::Bool);
+  EXPECT_TRUE(TypedValue(false).type() == TypedValue::Type::Bool);
 
-  EXPECT_TRUE(TypedValue(std::string("form string class")).type_ ==
+  EXPECT_TRUE(TypedValue(std::string("form string class")).type() ==
               TypedValue::Type::String);
-  EXPECT_TRUE(TypedValue("form c-string").type_ == TypedValue::Type::String);
+  EXPECT_TRUE(TypedValue("form c-string").type() == TypedValue::Type::String);
 
-  EXPECT_TRUE(TypedValue(0).type_ == TypedValue::Type::Int);
-  EXPECT_TRUE(TypedValue(42).type_ == TypedValue::Type::Int);
+  EXPECT_TRUE(TypedValue(0).type() == TypedValue::Type::Int);
+  EXPECT_TRUE(TypedValue(42).type() == TypedValue::Type::Int);
 
-  EXPECT_TRUE(TypedValue(0.0f).type_ == TypedValue::Type::Float);
-  EXPECT_TRUE(TypedValue(42.5f).type_ == TypedValue::Type::Float);
+  EXPECT_TRUE(TypedValue(0.0).type() == TypedValue::Type::Double);
+  EXPECT_TRUE(TypedValue(42.5).type() == TypedValue::Type::Double);
 }
 
 TEST(TypedValue, CreationValues) {
@@ -65,7 +63,7 @@ TEST(TypedValue, CreationValues) {
 
   EXPECT_EQ(TypedValue(55).Value<int>(), 55);
 
-  EXPECT_FLOAT_EQ(TypedValue(66.6f).Value<float>(), 66.6f);
+  EXPECT_FLOAT_EQ(TypedValue(66.6).Value<double>(), 66.6);
 }
 
 TEST(TypedValue, Equals) {
@@ -75,22 +73,26 @@ TEST(TypedValue, Equals) {
   EXPECT_PROP_EQ(TypedValue(42), TypedValue(42));
   EXPECT_PROP_NE(TypedValue(0), TypedValue(1));
 
-  EXPECT_PROP_NE(TypedValue(0.5f), TypedValue(0.12f));
-  EXPECT_PROP_EQ(TypedValue(0.123f), TypedValue(0.123f));
+  EXPECT_PROP_NE(TypedValue(0.5), TypedValue(0.12));
+  EXPECT_PROP_EQ(TypedValue(0.123), TypedValue(0.123));
 
-  EXPECT_PROP_EQ(TypedValue(2), TypedValue(2.0f));
-  EXPECT_PROP_NE(TypedValue(2), TypedValue(2.1f));
+  EXPECT_PROP_EQ(TypedValue(2), TypedValue(2.0));
+  EXPECT_PROP_NE(TypedValue(2), TypedValue(2.1));
 
   EXPECT_PROP_NE(TypedValue("str1"), TypedValue("str2"));
   EXPECT_PROP_EQ(TypedValue("str3"), TypedValue("str3"));
   EXPECT_PROP_EQ(TypedValue(std::string("str3")), TypedValue("str3"));
+
+  EXPECT_PROP_NE(TypedValue(std::vector<TypedValue>{1}), TypedValue(1));
+  EXPECT_PROP_EQ(TypedValue(std::vector<TypedValue>{1, true, "a"}),
+                 TypedValue(std::vector<TypedValue>{1, true, "a"}));
 }
 
 TEST(TypedValue, Less) {
   // not_bool_type < bool -> exception
-  TypedValueStore<> props = MakePropsAllTypes();
-  for (int i = 0; i < props.size() + 1; ++i) {
-    if (props.at(i).type_ == TypedValue::Type::Bool) continue;
+  auto props = MakePropsAllTypes();
+  for (int i = 0; i < (int)props.size(); ++i) {
+    if (props.at(i).type() == TypedValue::Type::Bool) continue;
     // the comparison should raise an exception
     // cast to (void) so the compiler does not complain about unused comparison
     // result
@@ -99,8 +101,8 @@ TEST(TypedValue, Less) {
 
   // not_bool_type < Null = Null
   props = MakePropsAllTypes();
-  for (int i = 0; i < props.size() + 1; ++i) {
-    if (props.at(i).type_ == TypedValue::Type::Bool) continue;
+  for (int i = 0; i < (int)props.size(); ++i) {
+    if (props.at(i).type() == TypedValue::Type::Bool) continue;
     EXPECT_PROP_ISNULL(props.at(i) < TypedValue::Null);
   }
 
@@ -109,16 +111,16 @@ TEST(TypedValue, Less) {
   EXPECT_PROP_FALSE(TypedValue(2) < TypedValue(2));
   EXPECT_PROP_FALSE(TypedValue(3) < TypedValue(2));
 
-  // float tests
-  EXPECT_PROP_TRUE(TypedValue(2.1f) < TypedValue(2.5f));
-  EXPECT_PROP_FALSE(TypedValue(2.0f) < TypedValue(2.0f));
-  EXPECT_PROP_FALSE(TypedValue(2.5f) < TypedValue(2.4f));
+  // double tests
+  EXPECT_PROP_TRUE(TypedValue(2.1) < TypedValue(2.5));
+  EXPECT_PROP_FALSE(TypedValue(2.0) < TypedValue(2.0));
+  EXPECT_PROP_FALSE(TypedValue(2.5) < TypedValue(2.4));
 
-  // implicit casting int->float
-  EXPECT_PROP_TRUE(TypedValue(2) < TypedValue(2.1f));
-  EXPECT_PROP_FALSE(TypedValue(2.1f) < TypedValue(2));
-  EXPECT_PROP_FALSE(TypedValue(2) < TypedValue(1.5f));
-  EXPECT_PROP_TRUE(TypedValue(1.5f) < TypedValue(2));
+  // implicit casting int->double
+  EXPECT_PROP_TRUE(TypedValue(2) < TypedValue(2.1));
+  EXPECT_PROP_FALSE(TypedValue(2.1) < TypedValue(2));
+  EXPECT_PROP_FALSE(TypedValue(2) < TypedValue(1.5));
+  EXPECT_PROP_TRUE(TypedValue(1.5) < TypedValue(2));
 
   // string tests
   EXPECT_PROP_TRUE(TypedValue("a") < TypedValue("b"));
@@ -130,15 +132,15 @@ TEST(TypedValue, LogicalNot) {
   EXPECT_PROP_EQ(!TypedValue(true), TypedValue(false));
   EXPECT_PROP_ISNULL(!TypedValue::Null);
   EXPECT_THROW(!TypedValue(0), TypedValueException);
-  EXPECT_THROW(!TypedValue(0.2f), TypedValueException);
+  EXPECT_THROW(!TypedValue(0.2), TypedValueException);
   EXPECT_THROW(!TypedValue("something"), TypedValueException);
 }
 
 TEST(TypedValue, UnaryMinus) {
-  EXPECT_TRUE((-TypedValue::Null).type_ == TypedValue::Type::Null);
+  EXPECT_TRUE((-TypedValue::Null).type() == TypedValue::Type::Null);
 
   EXPECT_PROP_EQ((-TypedValue(2).Value<int>()), -2);
-  EXPECT_FLOAT_EQ((-TypedValue(2.0f).Value<float>()), -2.0f);
+  EXPECT_FLOAT_EQ((-TypedValue(2.0).Value<double>()), -2.0);
 
   EXPECT_THROW(-TypedValue(true), TypedValueException);
   EXPECT_THROW(-TypedValue("something"), TypedValueException);
@@ -155,24 +157,30 @@ TEST(TypedValue, UnaryMinus) {
  *  the results.
  */
 void ExpectArithmeticThrowsAndNull(
-    bool string_ok,
+    bool string_list_ok,
     std::function<TypedValue(const TypedValue&, const TypedValue&)> op) {
   // arithmetic ops that raise
-  TypedValueStore<> props = MakePropsAllTypes();
-  for (int i = 0; i < props.size() + 1; ++i) {
-    EXPECT_THROW(op(TypedValue(true), props.at(i)), TypedValueException);
-    EXPECT_THROW(op(props.at(i), TypedValue(true)), TypedValueException);
-    if (!string_ok) {
+  auto props = MakePropsAllTypes();
+  for (int i = 0; i < (int)props.size(); ++i) {
+    if (!string_list_ok || props.at(i).type() == TypedValue::Type::String) {
+      EXPECT_THROW(op(TypedValue(true), props.at(i)), TypedValueException);
+      EXPECT_THROW(op(props.at(i), TypedValue(true)), TypedValueException);
+    }
+    if (!string_list_ok) {
       EXPECT_THROW(op(TypedValue("some"), props.at(i)), TypedValueException);
       EXPECT_THROW(op(props.at(i), TypedValue("some")), TypedValueException);
+      EXPECT_THROW(op(TypedValue("[1]"), props.at(i)), TypedValueException);
+      EXPECT_THROW(op(props.at(i), TypedValue("[]")), TypedValueException);
     }
   }
 
   // null resulting ops
   props = MakePropsAllTypes();
-  for (int i = 0; i < props.size() + 1; ++i) {
-    if (props.at(i).type_ == TypedValue::Type::Bool) continue;
-    if (!string_ok && props.at(i).type_ == TypedValue::Type::String) continue;
+  for (int i = 0; i < (int)props.size(); ++i) {
+    if (props.at(i).type() == TypedValue::Type::Bool) continue;
+    if (!string_list_ok && (props.at(i).type() == TypedValue::Type::String ||
+                            props.at(i).type() == TypedValue::Type::List))
+      continue;
 
     EXPECT_PROP_ISNULL(op(props.at(i), TypedValue::Null));
     EXPECT_PROP_ISNULL(op(TypedValue::Null, props.at(i)));
@@ -185,17 +193,28 @@ TEST(TypedValue, Sum) {
 
   // sum of props of the same type
   EXPECT_EQ((TypedValue(2) + TypedValue(3)).Value<int>(), 5);
-  EXPECT_FLOAT_EQ((TypedValue(2.5f) + TypedValue(1.25f)).Value<float>(), 3.75);
+  EXPECT_FLOAT_EQ((TypedValue(2.5) + TypedValue(1.25)).Value<double>(), 3.75);
   EXPECT_EQ((TypedValue("one") + TypedValue("two")).Value<std::string>(),
             "onetwo");
 
   // sum of string and numbers
   EXPECT_EQ((TypedValue("one") + TypedValue(1)).Value<std::string>(), "one1");
   EXPECT_EQ((TypedValue(1) + TypedValue("one")).Value<std::string>(), "1one");
-  EXPECT_EQ((TypedValue("one") + TypedValue(3.2f)).Value<std::string>(),
+  EXPECT_EQ((TypedValue("one") + TypedValue(3.2)).Value<std::string>(),
             "one3.2");
-  EXPECT_EQ((TypedValue(3.2f) + TypedValue("one")).Value<std::string>(),
+  EXPECT_EQ((TypedValue(3.2) + TypedValue("one")).Value<std::string>(),
             "3.2one");
+  std::vector<TypedValue> in = {1, 2, true, "a"};
+  std::vector<TypedValue> out1 = {2, 1, 2, true, "a"};
+  std::vector<TypedValue> out2 = {1, 2, true, "a", 2};
+  std::vector<TypedValue> out3 = {1, 2, true, "a", 1, 2, true, "a"};
+  EXPECT_PROP_EQ(
+      (TypedValue(2) + TypedValue(in)).Value<std::vector<TypedValue>>(), out1);
+  std::cerr << (TypedValue(2) + TypedValue(in)) << "\n";
+  EXPECT_PROP_EQ(
+      (TypedValue(in) + TypedValue(2)).Value<std::vector<TypedValue>>(), out2);
+  EXPECT_PROP_EQ(
+      (TypedValue(in) + TypedValue(in)).Value<std::vector<TypedValue>>(), out3);
 }
 
 TEST(TypedValue, Difference) {
@@ -204,11 +223,11 @@ TEST(TypedValue, Difference) {
 
   // difference of props of the same type
   EXPECT_EQ((TypedValue(2) - TypedValue(3)).Value<int>(), -1);
-  EXPECT_FLOAT_EQ((TypedValue(2.5f) - TypedValue(2.25f)).Value<float>(), 0.25);
+  EXPECT_FLOAT_EQ((TypedValue(2.5) - TypedValue(2.25)).Value<double>(), 0.25);
 
   // implicit casting
-  EXPECT_FLOAT_EQ((TypedValue(2) - TypedValue(0.5f)).Value<float>(), 1.5f);
-  EXPECT_FLOAT_EQ((TypedValue(2.5f) - TypedValue(2)).Value<float>(), 0.5f);
+  EXPECT_FLOAT_EQ((TypedValue(2) - TypedValue(0.5)).Value<double>(), 1.5);
+  EXPECT_FLOAT_EQ((TypedValue(2.5) - TypedValue(2)).Value<double>(), 0.5);
 }
 
 TEST(TypedValue, Divison) {
@@ -218,11 +237,11 @@ TEST(TypedValue, Divison) {
   EXPECT_PROP_EQ(TypedValue(10) / TypedValue(2), TypedValue(5));
   EXPECT_PROP_EQ(TypedValue(10) / TypedValue(4), TypedValue(2));
 
-  EXPECT_PROP_EQ(TypedValue(10.0f) / TypedValue(2.0f), TypedValue(5.0f));
-  EXPECT_FLOAT_EQ((TypedValue(10.0f) / TypedValue(4.0f)).Value<float>(), 2.5f);
+  EXPECT_PROP_EQ(TypedValue(10.0) / TypedValue(2.0), TypedValue(5.0));
+  EXPECT_FLOAT_EQ((TypedValue(10.0) / TypedValue(4.0)).Value<double>(), 2.5);
 
-  EXPECT_FLOAT_EQ((TypedValue(10) / TypedValue(4.0f)).Value<float>(), 2.5f);
-  EXPECT_FLOAT_EQ((TypedValue(10.0f) / TypedValue(4)).Value<float>(), 2.5f);
+  EXPECT_FLOAT_EQ((TypedValue(10) / TypedValue(4.0)).Value<double>(), 2.5);
+  EXPECT_FLOAT_EQ((TypedValue(10.0) / TypedValue(4)).Value<double>(), 2.5);
 }
 
 TEST(TypedValue, Multiplication) {
@@ -230,12 +249,10 @@ TEST(TypedValue, Multiplication) {
       false, [](const TypedValue& a, const TypedValue& b) { return a * b; });
 
   EXPECT_PROP_EQ(TypedValue(10) * TypedValue(2), TypedValue(20));
-  EXPECT_FLOAT_EQ((TypedValue(12.5f) * TypedValue(6.6f)).Value<float>(),
-                  12.5f * 6.6f);
-  EXPECT_FLOAT_EQ((TypedValue(10) * TypedValue(4.5f)).Value<float>(),
-                  10 * 4.5f);
-  EXPECT_FLOAT_EQ((TypedValue(10.2f) * TypedValue(4)).Value<float>(),
-                  10.2f * 4);
+  EXPECT_FLOAT_EQ((TypedValue(12.5) * TypedValue(6.6)).Value<double>(),
+                  12.5 * 6.6);
+  EXPECT_FLOAT_EQ((TypedValue(10) * TypedValue(4.5)).Value<double>(), 10 * 4.5);
+  EXPECT_FLOAT_EQ((TypedValue(10.2) * TypedValue(4)).Value<double>(), 10.2 * 4);
 }
 
 TEST(TypedValue, Modulo) {
@@ -245,23 +262,22 @@ TEST(TypedValue, Modulo) {
   EXPECT_PROP_EQ(TypedValue(10) % TypedValue(2), TypedValue(0));
   EXPECT_PROP_EQ(TypedValue(10) % TypedValue(4), TypedValue(2));
 
-  EXPECT_PROP_EQ(TypedValue(10.0f) % TypedValue(2.0f), TypedValue(0.0f));
-  EXPECT_FLOAT_EQ((TypedValue(10.0f) % TypedValue(3.25f)).Value<float>(),
-                  0.25f);
+  EXPECT_PROP_EQ(TypedValue(10.0) % TypedValue(2.0), TypedValue(0.0));
+  EXPECT_FLOAT_EQ((TypedValue(10.0) % TypedValue(3.25)).Value<double>(), 0.25);
 
-  EXPECT_FLOAT_EQ((TypedValue(10) % TypedValue(4.0f)).Value<float>(), 2.0f);
-  EXPECT_FLOAT_EQ((TypedValue(10.0f) % TypedValue(4)).Value<float>(), 2.0f);
+  EXPECT_FLOAT_EQ((TypedValue(10) % TypedValue(4.0)).Value<double>(), 2.0);
+  EXPECT_FLOAT_EQ((TypedValue(10.0) % TypedValue(4)).Value<double>(), 2.0);
 }
 
 TEST(TypedValue, TypeIncompatibility) {
-  TypedValueStore<> props = MakePropsAllTypes();
+  auto props = MakePropsAllTypes();
 
   // iterate over all the props, plus one, what will return
   // the Null property, which must be incompatible with all
   // the others
-  for (int i = 0; i < props.size() + 1; ++i)
-    for (int j = 0; j < props.size() + 1; ++j)
-      EXPECT_EQ(props.at(i).type_ == props.at(j).type_, i == j);
+  for (int i = 0; i < (int)props.size(); ++i)
+    for (int j = 0; j < (int)props.size(); ++j)
+      EXPECT_EQ(props.at(i).type() == props.at(j).type(), i == j);
 }
 
 /**
@@ -274,16 +290,16 @@ TEST(TypedValue, TypeIncompatibility) {
  */
 void TestLogicalThrows(
     std::function<TypedValue(const TypedValue&, const TypedValue&)> op) {
-  TypedValueStore<> props = MakePropsAllTypes();
-  for (int i = 0; i < props.size() + 1; ++i) {
+  auto props = MakePropsAllTypes();
+  for (int i = 0; i < (int)props.size(); ++i) {
     auto p1 = props.at(i);
-    for (int j = 0; j < props.size() + 1; ++j) {
+    for (int j = 0; j < (int)props.size(); ++j) {
       auto p2 = props.at(j);
       // skip situations when both p1 and p2 are either bool or null
-      auto p1_ok = p1.type_ == TypedValue::Type::Bool ||
-                   p1.type_ == TypedValue::Type::Null;
-      auto p2_ok = p2.type_ == TypedValue::Type::Bool ||
-                   p2.type_ == TypedValue::Type::Null;
+      auto p1_ok = p1.type() == TypedValue::Type::Bool ||
+                   p1.type() == TypedValue::Type::Null;
+      auto p2_ok = p2.type() == TypedValue::Type::Bool ||
+                   p2.type() == TypedValue::Type::Null;
       if (p1_ok && p2_ok) continue;
 
       EXPECT_THROW(op(p1, p2), TypedValueException);
diff --git a/tests/unit/typed_value_store.cpp b/tests/unit/typed_value_store.cpp
deleted file mode 100644
index 12fe0bded..000000000
--- a/tests/unit/typed_value_store.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-//
-// Copyright 2017 Memgraph
-// Created by Florijan Stamenkovic on 24.01.17..
-//
-#include <vector>
-
-#include "gtest/gtest.h"
-
-#include "storage/typed_value_store.hpp"
-
-using std::string;
-
-TEST(TypedValueStore, At) {
-  std::string some_string = "something";
-
-  TypedValueStore<> props;
-  EXPECT_EQ(TypedValue(props.at(0)).type_, TypedValue::Type::Null);
-  props.set(0, some_string);
-  EXPECT_EQ(TypedValue(props.at(0)).Value<string>(), some_string);
-  props.set(120, 42);
-  EXPECT_EQ(TypedValue(props.at(120)).Value<int>(), 42);
-}
-
-TEST(TypedValueStore, AtNull) {
-  TypedValueStore<> props;
-  EXPECT_EQ(props.at(0).type_, TypedValue::Type::Null);
-  EXPECT_EQ(props.at(100).type_, TypedValue::Type::Null);
-
-  // set one prop and test it's not null
-  props.set(0, true);
-  EXPECT_NE(props.at(0).type_, TypedValue::Type::Null);
-  EXPECT_EQ(props.at(100).type_, TypedValue::Type::Null);
-}
-
-TEST(TypedValueStore, Remove) {
-  // set some props
-  TypedValueStore<> props;
-  props.set(11, "a");
-  props.set(30, "b");
-  EXPECT_NE(props.at(11).type_, TypedValue::Type::Null);
-  EXPECT_NE(props.at(30).type_, TypedValue::Type::Null);
-  EXPECT_EQ(props.size(), 2);
-
-  props.erase(11);
-  EXPECT_EQ(props.size(), 1);
-  EXPECT_EQ(props.at(11).type_, TypedValue::Type::Null);
-
-  EXPECT_EQ(props.erase(30), 1);
-  EXPECT_EQ(props.size(), 0);
-  EXPECT_EQ(props.at(30).type_, TypedValue::Type::Null);
-
-  EXPECT_EQ(props.erase(1000), 0);
-}
-
-TEST(TypedValueStore, Replace) {
-  TypedValueStore<> props;
-  props.set(10, 42);
-  EXPECT_EQ(props.at(10).Value<int>(), 42);
-  props.set(10, 0.25f);
-  EXPECT_EQ(props.at(10).type_, TypedValue::Type::Float);
-  EXPECT_FLOAT_EQ(props.at(10).Value<float>(), 0.25);
-}
-
-TEST(TypedValueStore, Size) {
-  TypedValueStore<> props;
-  EXPECT_EQ(props.size(), 0);
-
-  props.set(0, "something");
-  EXPECT_EQ(props.size(), 1);
-  props.set(0, true);
-  EXPECT_EQ(props.size(), 1);
-  props.set(1, true);
-  EXPECT_EQ(props.size(), 2);
-
-  for (int i = 0; i < 100; ++i) props.set(i + 20, true);
-  EXPECT_EQ(props.size(), 102);
-
-  props.erase(0);
-  EXPECT_EQ(props.size(), 101);
-  props.erase(0);
-  EXPECT_EQ(props.size(), 101);
-  props.erase(1);
-  EXPECT_EQ(props.size(), 100);
-}
-
-TEST(TypedValueStore, Accept) {
-  int count_props = 0;
-  int count_finish = 0;
-
-  auto handler = [&](const uint32_t key, const TypedValue& prop) {
-    count_props += 1;
-  };
-  auto finish = [&]() { count_finish += 1; };
-
-  TypedValueStore<uint32_t> props;
-  props.Accept(handler, finish);
-  EXPECT_EQ(count_props, 0);
-  EXPECT_EQ(count_finish, 1);
-
-  props.Accept(handler);
-  EXPECT_EQ(count_props, 0);
-  EXPECT_EQ(count_finish, 1);
-
-  props.set(0, 20);
-  props.set(1, "bla");
-
-  props.Accept(handler, finish);
-  EXPECT_EQ(count_props, 2);
-  EXPECT_EQ(count_finish, 2);
-}