diff --git a/CHANGELOG.md b/CHANGELOG.md
index 70166e06..ee34068f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
 - Added FilterBoxAABB and FilterSphereAABB as examples for filtering a PH-Tree with box keys
   [#33](https://github.com/tzaeschke/phtree-cpp/issues/33)
 ### Changed
+- **POTENTIALLY BREAKING CHANGE**: Removed internal use of std::optional(). This may break usage of emplace() that
+  did not provide exactly matching constructor parameter types. E.g. previously an `int` parameter would match
+  a `size_t` constructor argument type. This now fails. [#38](https://github.com/tzaeschke/phtree-cpp/issues/38)
 - Removed restrictions on bazel version [#35](https://github.com/tzaeschke/phtree-cpp/issues/35)
 - **API BREAKING CHANGE**: API of filters have been changed to be more correct, explicit and flexible.
   [#21](https://github.com/tzaeschke/phtree-cpp/issues/21)
diff --git a/phtree/phtree_test.cc b/phtree/phtree_test.cc
index 4c17befe..b70116b1 100644
--- a/phtree/phtree_test.cc
+++ b/phtree/phtree_test.cc
@@ -73,6 +73,10 @@ struct Id {
         ++construct_count_;
     }
 
+    explicit Id(const int i) : _i{i} {
+        ++construct_count_;
+    }
+
     Id(const Id& other) {
         ++copy_construct_count_;
         _i = other._i;
diff --git a/phtree/v16/entry.h b/phtree/v16/entry.h
index c9964f9e..8dd0cbbf 100644
--- a/phtree/v16/entry.h
+++ b/phtree/v16/entry.h
@@ -21,16 +21,12 @@
 #include "node.h"
 #include <cassert>
 #include <memory>
-#include <optional>
 
 namespace improbable::phtree::v16 {
 
 template <dimension_t DIM, typename T, typename SCALAR>
 class Node;
 
-template <dimension_t DIM, typename T, typename SCALAR>
-struct EntryVariant;
-
 /*
  * Nodes in the PH-Tree contain up to 2^DIM Entries, one in each geometric quadrant.
  * Entries can contain two types of data:
@@ -73,20 +69,15 @@ class Entry {
     /*
      * Construct entry with existing T.
      */
-    Entry(const KeyT& k, std::optional<ValueT>&& value) noexcept
-    : kd_key_{k}, value_{std::move(value)}, union_type_{VALUE}, postfix_len_{0} {
-        //        value.reset();  // std::optional's move constructor does not destruct the previous
-    }
+    Entry(const KeyT& k, ValueT&& value) noexcept
+    : kd_key_{k}, value_{std::move(value)}, union_type_{VALUE}, postfix_len_{0} {}
 
     /*
      * Construct entry with new T or moved T.
      */
     template <typename... Args>
     explicit Entry(const KeyT& k, Args&&... args) noexcept
-    : kd_key_{k}
-    , value_{std::in_place, std::forward<Args>(args)...}
-    , union_type_{VALUE}
-    , postfix_len_{0} {}
+    : kd_key_{k}, value_{std::forward<Args>(args)...}, union_type_{VALUE}, postfix_len_{0} {}
 
     Entry(const Entry& other) = delete;
     Entry& operator=(const Entry& other) = delete;
@@ -123,7 +114,7 @@ class Entry {
 
     [[nodiscard]] T& GetValue() const {
         assert(union_type_ == VALUE);
-        return const_cast<T&>(*value_);
+        return const_cast<T&>(value_);
     }
 
     [[nodiscard]] NodeT& GetNode() const {
@@ -154,7 +145,7 @@ class Entry {
         return parent_postfix_len - GetNodePostfixLen() - 1 > 0;
     }
 
-    [[nodiscard]] std::optional<ValueT>&& ExtractValue() noexcept {
+    [[nodiscard]] ValueT&& ExtractValue() noexcept {
         assert(IsValue());
         union_type_ = EMPTY;
         return std::move(value_);
@@ -182,7 +173,7 @@ class Entry {
         if (union_type_ == NODE) {
             new (&node_) std::unique_ptr<NodeT>{std::move(other.node_)};
         } else if (union_type_ == VALUE) {
-            new (&value_) std::optional<ValueT>{std::move(other.value_)};
+            new (&value_) ValueT{std::move(other.value_)};
         } else {
             assert(false && "Assigning from an EMPTY variant is a waste of time.");
         }
@@ -190,7 +181,7 @@ class Entry {
 
     void DestroyUnion() noexcept {
         if (union_type_ == VALUE) {
-            value_.~optional();
+            value_.~ValueT();
         } else if (union_type_ == NODE) {
             node_.~unique_ptr();
         } else {
@@ -202,16 +193,16 @@ class Entry {
     KeyT kd_key_;
     union {
         std::unique_ptr<NodeT> node_;
-        std::optional<ValueT> value_;
+        ValueT value_;
     };
-    alignas(2) std::uint16_t union_type_;
+    std::uint16_t union_type_;
     // The length (number of bits) of post fixes (the part of the coordinate that is 'below' the
     // current node). If a variable prefix_len would refer to the number of bits in this node's
     // prefix, and if we assume 64 bit values, the following would always hold:
     // prefix_len + 1 + postfix_len = 64.
     // The '+1' accounts for the 1 bit that is represented by the local node's hypercube,
     // i.e. the same bit that is used to create the lookup keys in entries_.
-    alignas(2) std::uint16_t postfix_len_;
+    std::uint16_t postfix_len_;
 };
 
 }  // namespace improbable::phtree::v16
