diff --git a/src/cpp/include/nola/owning_ptr.hpp b/src/cpp/include/nola/owning_ptr.hpp
index 6051bf4b4c63b6272582c1824cdde0c1ab29aec9..154d488851781cd253b72a19e78ac87687703067 100644
--- a/src/cpp/include/nola/owning_ptr.hpp
+++ b/src/cpp/include/nola/owning_ptr.hpp
@@ -35,6 +35,14 @@ public:
 
   owning_ptr(pointer ptr, allocator_type const& alloc);
 
+  template <typename U, typename OtherAlloc>
+  explicit owning_ptr(owning_ptr<U, OtherAlloc>&& other) noexcept
+    requires std::convertible_to<U*, T*>;
+
+  template <typename U, typename OtherAlloc>
+  auto operator=(owning_ptr<U, OtherAlloc>&& other) noexcept -> owning_ptr&
+    requires std::convertible_to<U*, T*>;
+
 private:
   owning_ptr(owning_ptr const&) = default;
   auto operator=(owning_ptr const&) -> owning_ptr& = default;
@@ -65,6 +73,8 @@ public:
   void reset(pointer ptr) noexcept;
   void reset() noexcept;
 
+  auto get_allocator() const noexcept -> allocator_type { return alloc_; }
+
 private:
   pointer value_ = nullptr;
   internal_allocator alloc_;
@@ -97,6 +107,26 @@ owning_ptr<T, Alloc>::~owning_ptr()
   }
 }
 
+template <typename T, typename Alloc>
+template <typename U, typename OtherAlloc>
+owning_ptr<T, Alloc>::owning_ptr(owning_ptr<U, OtherAlloc>&& other) noexcept
+  requires std::convertible_to<U*, T*>
+: value_(other.release()), alloc_(std::move(other.get_allocator()))
+{
+}
+
+template <typename T, typename Alloc>
+template <typename U, typename OtherAlloc>
+auto owning_ptr<T, Alloc>::operator=(owning_ptr<U, OtherAlloc>&& other) noexcept -> owning_ptr&
+  requires std::convertible_to<U*, T*>
+{
+  if (*this != other) {
+    value_ = other.release();
+    alloc_ = std::move(other.get_allocator());
+  }
+  return *this;
+}
+
 template <typename T1, typename Alloc1, typename T2, typename Alloc>
 auto operator==(owning_ptr<T1, Alloc1> const& lhs, owning_ptr<T2, Alloc> const& rhs) noexcept
   -> bool
diff --git a/test/unit/cpp/nola/owning_ptr.t.cpp b/test/unit/cpp/nola/owning_ptr.t.cpp
index d316c20d53ec928518a8f35c86ba5f05afb31d6b..ac60f27ff6c9b8aad9ff1ef3c35a7bade1b8402a 100644
--- a/test/unit/cpp/nola/owning_ptr.t.cpp
+++ b/test/unit/cpp/nola/owning_ptr.t.cpp
@@ -22,6 +22,28 @@ public:
   auto get() const -> int { return i; }
 };
 
+class Base {
+public:
+  Base() = default;
+  virtual auto get() const -> int = 0;
+  virtual ~Base() = default;
+  Base(Base const&) = default;
+  Base(Base&&) = default;
+  auto operator=(Base const&) -> Base& = default;
+  auto operator=(Base&&) -> Base& = default;
+};
+
+class Derived : public Base {
+public:
+  Derived() = default;
+  auto get() const -> int override { return 3; }
+  ~Derived() override = default;
+  Derived(Derived const&) = default;
+  Derived(Derived&&) = default;
+  auto operator=(Derived const&) -> Derived& = default;
+  auto operator=(Derived&&) -> Derived& = default;
+};
+
 TEST_CASE("01. owning_ptr construction", "[all]")
 {
   auto ptr = nola::make_owning<S>(3);
@@ -34,3 +56,11 @@ TEST_CASE("01. owning_ptr construction", "[all]")
   REQUIRE((*new_ptr).get() == 5);
   REQUIRE((*ptr).get() == 3);
 }
+
+TEST_CASE("02. Test Construction of Derived")
+{
+  auto ptr = nola::make_owning<Derived>();
+  REQUIRE(ptr->get() == 3);
+
+  auto base_ptr = nola::owning_ptr<Base>(ptr.clone());
+}