diff --git a/README.md b/README.md
index 8c23fe2..51ebc21 100644
--- a/README.md
+++ b/README.md
@@ -83,6 +83,8 @@ int main() {
 }
 ```
 
+As with `std::shared_ptr`/`std::weak_ptr`, if you need to obtain an observer pointer to an object when you only have `this` (i.e., from a member function), you can inherit from `oup::enable_observer_from_this<T>` to gain access to the `observer_from_this()` member function. This function will return a valid observer pointer as long as the object is owned by a unique or sealed pointer, and will return `nullptr` in all other cases.
+
 
 ## Limitations
 
@@ -192,4 +194,4 @@ Detail of the benchmarks:
 
 ## Alternative implementation
 
-An alternative implementation of an "observable unique pointer" can be found [here](https://www.codeproject.com/articles/1011134/smart-observers-to-use-with-unique-ptr). It does not compile out of the box with gcc unfortunately, but it does contain more features (like creating an observer pointer from a raw `this`) and lacks others (their `make_observable` always performs two allocations). Have a look to check if this better suits your needs.
+An alternative implementation of an "observable unique pointer" can be found [here](https://www.codeproject.com/articles/1011134/smart-observers-to-use-with-unique-ptr). It does not compile out of the box with gcc unfortunately and lacks certain features (their `make_observable` always performs two allocations). Have a look to check if this better suits your needs.
diff --git a/include/oup/observable_unique_ptr.hpp b/include/oup/observable_unique_ptr.hpp
index 02cb067..ca66c17 100644
--- a/include/oup/observable_unique_ptr.hpp
+++ b/include/oup/observable_unique_ptr.hpp
@@ -11,7 +11,11 @@ namespace oup {
 template<typename T>
 class observer_ptr;
 
+template<typename T>
+class enable_observer_from_this;
+
 namespace details {
+
 struct control_block {
     enum flag_elements {
         flag_none = 0,
@@ -34,6 +38,7 @@ template<typename T, typename Deleter>
 struct ptr_and_deleter : Deleter {
     T* data = nullptr;
 };
+
 }
 
 /// Simple default deleter
@@ -75,6 +80,9 @@ struct placement_delete
 };
 
 namespace details {
+
+struct enable_observer_from_this_base {};
+
 template<typename T, typename Deleter = oup::default_delete<T>>
 class observable_unique_ptr_base {
 protected:
@@ -106,6 +114,16 @@ class observable_unique_ptr_base {
         delete_and_pop_ref_(block, ptr_deleter.data, ptr_deleter);
     }
 
+    /// Fill in the observer pointer for objects inheriting from enable_observer_from_this.
+    void set_this_observer_() noexcept {
+        if constexpr (std::is_base_of_v<details::enable_observer_from_this_base, T>) {
+            if (ptr_deleter.data) {
+                ptr_deleter.data->this_observer.set_data_(block, ptr_deleter.data);
+                ++block->refcount;
+            }
+        }
+    }
+
     /// Private constructor using pre-allocated control block.
     /** \param ctrl The control block pointer
     *   \param value The pointer to own
@@ -292,6 +310,10 @@ class observable_unique_ptr_base {
     /** \param other The other pointer to swap with
     */
     void swap(observable_unique_ptr_base& other) noexcept {
+        if (&other == this) {
+            return;
+        }
+
         using std::swap;
         swap(block, other.block);
         swap(ptr_deleter, other.ptr_deleter);
@@ -345,6 +367,7 @@ class observable_unique_ptr_base {
         return ptr_deleter.data != nullptr;
     }
 };
+
 }
 
 /// Unique-ownership smart pointer, can be observed by observer_ptr, ownership can be released.
@@ -381,21 +404,6 @@ class observable_unique_ptr :
         return new control_block_type;
     }
 
-    static void pop_ref_(control_block_type* block) noexcept {
-        --block->refcount;
-        if (block->refcount == 0) {
-            delete block;
-        }
-    }
-
-    static void delete_and_pop_ref_(control_block_type* block, T* data, Deleter& deleter) noexcept {
-        deleter(data);
-
-        block->set_expired();
-
-        pop_ref_(block);
-    }
-
     // Friendship is required for conversions.
     template<typename U>
     friend class observer_ptr;
@@ -433,7 +441,9 @@ class observable_unique_ptr :
     *         using make_observable_unique() instead of this constructor.
     */
     explicit observable_unique_ptr(T* value) :
-        base(value != nullptr ? allocate_block_() : nullptr, value) {}
+        base(value != nullptr ? allocate_block_() : nullptr, value) {
+        base::set_this_observer_();
+    }
 
     /// Explicit ownership capture of a raw pointer, with customer deleter.
     /** \param value The raw pointer to take ownership of
@@ -443,7 +453,9 @@ class observable_unique_ptr :
     *         using make_observable_unique() instead of this constructor.
     */
     explicit observable_unique_ptr(T* value, Deleter del) :
-        base(value != nullptr ? allocate_block_() : nullptr, value, std::move(del)) {}
+        base(value != nullptr ? allocate_block_() : nullptr, value, std::move(del)) {
+        base::set_this_observer_();
+    }
 
     /// Transfer ownership by implicit casting
     /** \param value The pointer to take ownership from
@@ -474,7 +486,9 @@ class observable_unique_ptr :
     */
     template<typename U, typename D>
     observable_unique_ptr(observable_unique_ptr<U,D>&& manager, T* value) noexcept :
-        base(std::move(manager), value) {}
+        base(std::move(manager), value) {
+        base::set_this_observer_();
+    }
 
     /// Transfer ownership by explicit casting
     /** \param manager The smart pointer to take ownership from
@@ -485,7 +499,9 @@ class observable_unique_ptr :
     */
     template<typename U, typename D>
     observable_unique_ptr(observable_unique_ptr<U,D>&& manager, T* value, Deleter del) noexcept :
-        base(std::move(manager), value, del) {}
+        base(std::move(manager), value, del) {
+        base::set_this_observer_();
+    }
 
     /// Transfer ownership by implicit casting
     /** \param value The pointer to take ownership from
@@ -544,8 +560,10 @@ class observable_unique_ptr :
         // Delete the old pointer
         // (this follows std::unique_ptr specs)
         if (old_ptr) {
-            delete_and_pop_ref_(old_block, old_ptr, base::ptr_deleter);
+            base::delete_and_pop_ref_(old_block, old_ptr, base::ptr_deleter);
         }
+
+        base::set_this_observer_();
     }
 
     /// Releases ownership of the managed object and mark observers as expired.
@@ -608,7 +626,9 @@ class observable_sealed_ptr :
     *   \note This is used by make_observable_sealed().
     */
     observable_sealed_ptr(control_block_type* ctrl, T* value) noexcept :
-        base(ctrl, value, oup::placement_delete<T>{}) {}
+        base(ctrl, value, oup::placement_delete<T>{}) {
+        base::set_this_observer_();
+    }
 
     // Friendship is required for conversions.
     template<typename U>
@@ -744,7 +764,7 @@ observable_sealed_ptr<T> make_observable_sealed(Args&& ... args) {
     // Allocate memory
     constexpr std::size_t block_size = sizeof(block_type);
     constexpr std::size_t object_size = sizeof(T);
-    std::byte* buffer = new std::byte[block_size + object_size];
+    std::byte* buffer = reinterpret_cast<std::byte*>(operator new(block_size + object_size));
 
     try {
         // Construct control block and object
@@ -756,7 +776,7 @@ observable_sealed_ptr<T> make_observable_sealed(Args&& ... args) {
     } catch (...) {
         // Exception thrown during object construction,
         // clean up memory and let exception propagate
-        delete[] buffer;
+        delete buffer;
         throw;
     }
 }
@@ -835,6 +855,9 @@ class observer_ptr {
     // Friendship is required for conversions.
     template<typename U>
     friend class observer_ptr;
+    // Friendship is required for enable_observer_from_this.
+    template<typename U, typename D>
+    friend class details::observable_unique_ptr_base;
 
     using control_block = details::control_block;
 
@@ -848,6 +871,15 @@ class observer_ptr {
         }
     }
 
+    void set_data_(control_block* b, T* d) noexcept {
+        if (data) {
+            pop_ref_();
+        }
+
+        block = b;
+        data = d;
+    }
+
 public:
     /// Type of the pointed object
     using element_type = T;
@@ -936,12 +968,8 @@ class observer_ptr {
     */
     template<typename U, typename D, typename enable = std::enable_if_t<std::is_convertible_v<U*, T*>>>
     observer_ptr& operator=(const observable_unique_ptr<U,D>& owner) noexcept {
-        if (data) {
-            pop_ref_();
-        }
+        set_data_(owner.block, owner.ptr_deleter.data);
 
-        block = owner.block;
-        data = owner.ptr_deleter.data;
         if (block) {
             ++block->refcount;
         }
@@ -956,12 +984,8 @@ class observer_ptr {
     */
     template<typename U, typename enable = std::enable_if_t<std::is_convertible_v<U*, T*>>>
     observer_ptr& operator=(const observable_sealed_ptr<U>& owner) noexcept {
-        if (data) {
-            pop_ref_();
-        }
+        set_data_(owner.block, owner.ptr_deleter.data);
 
-        block = owner.block;
-        data = owner.ptr_deleter.data;
         if (block) {
             ++block->refcount;
         }
@@ -973,12 +997,12 @@ class observer_ptr {
     /** \param value The existing weak pointer to copy
     */
     observer_ptr& operator=(const observer_ptr& value) noexcept {
-        if (data) {
-            pop_ref_();
+        if (&value == this) {
+            return *this;
         }
 
-        block = value.block;
-        data = value.data;
+        set_data_(value.block, value.data);
+
         if (block) {
             ++block->refcount;
         }
@@ -993,12 +1017,12 @@ class observer_ptr {
     */
     template<typename U, typename enable = std::enable_if_t<std::is_convertible_v<U*, T*>>>
     observer_ptr& operator=(const observer_ptr<U>& value) noexcept {
-        if (data) {
-            pop_ref_();
+        if (&value == this) {
+            return *this;
         }
 
-        block = value.block;
-        data = value.data;
+        set_data_(value.block, value.data);
+
         if (block) {
             ++block->refcount;
         }
@@ -1012,13 +1036,9 @@ class observer_ptr {
     *         pointer is set to null and looses ownership.
     */
     observer_ptr& operator=(observer_ptr&& value) noexcept {
-        if (data) {
-            pop_ref_();
-        }
+        set_data_(value.block, value.data);
 
-        block = value.block;
         value.block = nullptr;
-        data = value.data;
         value.data = nullptr;
 
         return *this;
@@ -1033,13 +1053,9 @@ class observer_ptr {
     */
     template<typename U, typename enable = std::enable_if_t<std::is_convertible_v<U*, T*>>>
     observer_ptr& operator=(observer_ptr<U>&& value) noexcept {
-        if (data) {
-            pop_ref_();
-        }
+        set_data_(value.block, value.data);
 
-        block = value.block;
         value.block = nullptr;
-        data = value.data;
         value.data = nullptr;
 
         return *this;
@@ -1114,6 +1130,10 @@ class observer_ptr {
     /** \param other The other pointer to swap with
     */
     void swap(observer_ptr& other) noexcept {
+        if (&other == this) {
+            return;
+        }
+
         using std::swap;
         swap(block, other.block);
         swap(data, other.data);
@@ -1153,6 +1173,64 @@ bool operator!= (const observer_ptr<T>& first, const observer_ptr<U>& second) no
     return first.get() != second.get();
 }
 
+/// Enables creating an observer pointer from 'this'.
+/** If an object must be able to create an observer pointer to itself,
+*   without having direct access to the owner pointer (unique or sealed),
+*   then the object's class can inherit from enable_observer_from_this.
+*   This provides the observer_from_this() member function, which returns
+*   a new observer pointer to the object. For this mechanism to work,
+*   the class must inherit publicly from enable_observer_from_this,
+*   and the object must be owned by a unique or sealed pointer when
+*   calling observer_from_this(). If the latter condition is not satisfied,
+*   i.e., the object was allocated on the stack, or is owned by another
+*   type of smart pointer, then observer_from_this() will return nullptr.
+*/
+template<typename T>
+class enable_observer_from_this : public details::enable_observer_from_this_base {
+    mutable observer_ptr<T> this_observer;
+
+    // Friendship is required for assignment of the observer.
+    template<typename U, typename D>
+    friend class details::observable_unique_ptr_base;
+
+protected:
+    enable_observer_from_this() noexcept = default;
+
+    enable_observer_from_this(const enable_observer_from_this&) noexcept {
+        // Do not copy the other object's observer, this would be an
+        // invalid reference.
+    };
+
+    enable_observer_from_this(enable_observer_from_this&&) noexcept {
+        // Do not move the other object's observer, this would be an
+        // invalid reference.
+    };
+
+    ~enable_observer_from_this() noexcept = default;
+
+public:
+
+    /// Return an observer pointer to 'this'.
+    /** \return A new observer pointer pointing to 'this'.
+    *   \note If 'this' is not owned by a unique or sealed pointer, i.e., if
+    *   the object was allocated on the stack, or if it is owned by another
+    *   type of smart pointer, then this function will return nullptr.
+    */
+    observer_ptr<T> observer_from_this() {
+        return this_observer;
+    }
+
+    /// Return a const observer pointer to 'this'.
+    /** \return A new observer pointer pointing to 'this'.
+    *   \note If 'this' is not owned by a unique or sealed pointer, i.e., if
+    *   the object was allocated on the stack, or if it is owned by another
+    *   type of smart pointer, then this function will return nullptr.
+    */
+    observer_ptr<const T> observer_from_this() const {
+        return this_observer;
+    }
+};
+
 }
 
 #endif
diff --git a/tests/runtime_tests.cpp b/tests/runtime_tests.cpp
index b1304b6..fd29e73 100644
--- a/tests/runtime_tests.cpp
+++ b/tests/runtime_tests.cpp
@@ -748,6 +748,102 @@ TEST_CASE("owner move assignment operator valid to valid with deleter", "[owner_
     REQUIRE(mem_track.double_del() == 0u);
 }
 
+TEST_CASE("owner move assignment operator self to self", "[owner_assignment]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr ptr(new test_object);
+        ptr = std::move(ptr);
+        REQUIRE(instances == 0);
+        REQUIRE(ptr.get() == nullptr);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("owner move assignment operator self to self sealed", "[owner_assignment]") {
+    memory_tracker mem_track;
+
+    {
+        test_sptr ptr = oup::make_observable_sealed<test_object>();
+        ptr = std::move(ptr);
+        REQUIRE(instances == 0);
+        REQUIRE(ptr.get() == nullptr);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("owner move assignment operator self to self with deleter", "[owner_assignment]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr_with_deleter ptr(new test_object, test_deleter{42});
+        ptr = std::move(ptr);
+        REQUIRE(instances == 0);
+        REQUIRE(ptr.get() == nullptr);
+        REQUIRE(instances_deleter == 1);
+        REQUIRE(ptr.get_deleter().state_ == 0);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(instances_deleter == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("owner move assignment operator self to self empty", "[owner_assignment]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr ptr;
+        ptr = std::move(ptr);
+        REQUIRE(instances == 0);
+        REQUIRE(ptr.get() == nullptr);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("owner move assignment operator self to self empty sealed", "[owner_assignment]") {
+    memory_tracker mem_track;
+
+    {
+        test_sptr ptr;
+        ptr = std::move(ptr);
+        REQUIRE(instances == 0);
+        REQUIRE(ptr.get() == nullptr);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("owner move assignment operator self to self empty with deleter", "[owner_assignment]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr_with_deleter ptr;
+        ptr = std::move(ptr);
+        REQUIRE(instances == 0);
+        REQUIRE(ptr.get() == nullptr);
+        REQUIRE(instances_deleter == 1);
+        REQUIRE(ptr.get_deleter().state_ == 0);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(instances_deleter == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
 TEST_CASE("owner comparison valid ptr vs nullptr", "[owner_comparison]") {
     memory_tracker mem_track;
 
@@ -1291,6 +1387,52 @@ TEST_CASE("owner swap two instances with deleter", "[owner_utility]") {
     REQUIRE(mem_track.double_del() == 0u);
 }
 
+TEST_CASE("owner swap self", "[owner_utility]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr ptr(new test_object);
+        ptr.swap(ptr);
+        REQUIRE(instances == 1);
+        REQUIRE(ptr.get() != nullptr);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("owner swap self sealed", "[owner_utility]") {
+    memory_tracker mem_track;
+
+    {
+        test_sptr ptr = oup::make_observable_sealed<test_object>();
+        ptr.swap(ptr);
+        REQUIRE(instances == 1);
+        REQUIRE(ptr.get() != nullptr);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("owner swap self with deleter", "[owner_utility]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr_with_deleter ptr(new test_object, test_deleter{43});
+        ptr.swap(ptr);
+        REQUIRE(instances == 1);
+        REQUIRE(ptr.get() != nullptr);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(instances_deleter == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
 TEST_CASE("owner dereference", "[owner_utility]") {
     memory_tracker mem_track;
 
@@ -1986,6 +2128,23 @@ TEST_CASE("observer swap two different instances", "[observer_utility]") {
     REQUIRE(mem_track.double_del() == 0u);
 }
 
+TEST_CASE("observer swap self", "[observer_utility]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr ptr_owner(new test_object);
+        test_optr ptr(ptr_owner);
+        ptr.swap(ptr);
+        REQUIRE(instances == 1);
+        REQUIRE(ptr.get() == ptr_owner.get());
+        REQUIRE(ptr.expired() == false);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
 TEST_CASE("observer dereference", "[observer_utility]") {
     memory_tracker mem_track;
 
@@ -2118,6 +2277,59 @@ TEST_CASE("observer copy assignment operator empty to empty", "[observer_assignm
     REQUIRE(mem_track.double_del() == 0u);
 }
 
+TEST_CASE("observer copy assignment operator self to self", "[observer_assignment]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr ptr_owner{new test_object};
+        test_optr ptr{ptr_owner};
+        ptr = ptr;
+        REQUIRE(instances == 1);
+        REQUIRE(ptr.get() != nullptr);
+        REQUIRE(ptr.expired() == false);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("observer copy assignment operator self to self expired", "[observer_assignment]") {
+    memory_tracker mem_track;
+
+    {
+        test_optr ptr;
+        {
+            test_ptr ptr_owner{new test_object};
+            ptr = ptr_owner;
+        }
+        ptr = ptr;
+        REQUIRE(instances == 0);
+        REQUIRE(ptr.get() == nullptr);
+        REQUIRE(ptr.expired() == true);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("observer copy assignment operator self to self empty", "[observer_assignment]") {
+    memory_tracker mem_track;
+
+    {
+        test_optr ptr;
+        ptr = ptr;
+        REQUIRE(instances == 0);
+        REQUIRE(ptr.get() == nullptr);
+        REQUIRE(ptr.expired() == true);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
 TEST_CASE("observer move assignment operator valid to empty", "[observer_assignment]") {
     memory_tracker mem_track;
 
@@ -2190,6 +2402,59 @@ TEST_CASE("observer move assignment operator empty to empty", "[observer_assignm
     REQUIRE(mem_track.double_del() == 0u);
 }
 
+TEST_CASE("observer move assignment operator self to self", "[observer_assignment]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr ptr_owner{new test_object};
+        test_optr ptr{ptr_owner};
+        ptr = std::move(ptr);
+        REQUIRE(instances == 1);
+        REQUIRE(ptr.get() == nullptr);
+        REQUIRE(ptr.expired() == true);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("observer move assignment operator self to self expired", "[observer_assignment]") {
+    memory_tracker mem_track;
+
+    {
+        test_optr ptr;
+        {
+            test_ptr ptr_owner{new test_object};
+            ptr = ptr_owner;
+        }
+        ptr = std::move(ptr);
+        REQUIRE(instances == 0);
+        REQUIRE(ptr.get() == nullptr);
+        REQUIRE(ptr.expired() == true);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("observer move assignment operator self to self empty", "[observer_assignment]") {
+    memory_tracker mem_track;
+
+    {
+        test_optr ptr;
+        ptr = std::move(ptr);
+        REQUIRE(instances == 0);
+        REQUIRE(ptr.get() == nullptr);
+        REQUIRE(ptr.expired() == true);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
 TEST_CASE("observer acquiring assignment operator valid to empty", "[observer_assignment]") {
     memory_tracker mem_track;
 
@@ -2651,3 +2916,236 @@ TEST_CASE("pointers in vector", "[system_tests]") {
     REQUIRE(mem_track.leaks() == 0u);
     REQUIRE(mem_track.double_del() == 0u);
 }
+
+TEST_CASE("observer from this", "[observer_from_this]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr_from_this ptr{new test_object_observer_from_this};
+        const test_ptr_from_this& cptr = ptr;
+
+        test_optr_from_this optr_from_this = ptr->observer_from_this();
+        test_optr_from_this_const optr_from_this_const = cptr->observer_from_this();
+
+        REQUIRE(instances == 1);
+        REQUIRE(optr_from_this.expired() == false);
+        REQUIRE(optr_from_this_const.expired() == false);
+        REQUIRE(optr_from_this.get() == ptr.get());
+        REQUIRE(optr_from_this_const.get() == ptr.get());
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("observer from this sealed", "[observer_from_this]") {
+    memory_tracker mem_track;
+
+    {
+        test_sptr_from_this ptr = oup::make_observable_sealed<test_object_observer_from_this>();
+        const test_sptr_from_this& cptr = ptr;
+
+        test_optr_from_this optr_from_this = ptr->observer_from_this();
+        test_optr_from_this_const optr_from_this_const = cptr->observer_from_this();
+
+        REQUIRE(instances == 1);
+        REQUIRE(optr_from_this.expired() == false);
+        REQUIRE(optr_from_this_const.expired() == false);
+        REQUIRE(optr_from_this.get() == ptr.get());
+        REQUIRE(optr_from_this_const.get() == ptr.get());
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("observer from this derived", "[observer_from_this]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr_from_this_derived ptr{new test_object_observer_from_this_derived};
+        const test_ptr_from_this_derived& cptr = ptr;
+
+        test_optr_from_this optr_from_this = ptr->observer_from_this();
+        test_optr_from_this_const optr_from_this_const = cptr->observer_from_this();
+
+        REQUIRE(instances == 1);
+        REQUIRE(optr_from_this.expired() == false);
+        REQUIRE(optr_from_this_const.expired() == false);
+        REQUIRE(optr_from_this.get() == ptr.get());
+        REQUIRE(optr_from_this_const.get() == ptr.get());
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("observer from this after move", "[observer_from_this]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr_from_this ptr1{new test_object_observer_from_this};
+        test_ptr_from_this ptr2{std::move(ptr1)};
+        const test_ptr_from_this& cptr2 = ptr2;
+
+        test_optr_from_this optr_from_this = ptr2->observer_from_this();
+        test_optr_from_this_const optr_from_this_const = cptr2->observer_from_this();
+
+        REQUIRE(instances == 1);
+        REQUIRE(optr_from_this.expired() == false);
+        REQUIRE(optr_from_this_const.expired() == false);
+        REQUIRE(optr_from_this.get() == ptr2.get());
+        REQUIRE(optr_from_this_const.get() == ptr2.get());
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("observer from this after move sealed", "[observer_from_this]") {
+    memory_tracker mem_track;
+
+    {
+        test_sptr_from_this ptr1 = oup::make_observable_sealed<test_object_observer_from_this>();
+        test_sptr_from_this ptr2{std::move(ptr1)};
+        const test_sptr_from_this& cptr2 = ptr2;
+
+        test_optr_from_this optr_from_this = ptr2->observer_from_this();
+        test_optr_from_this_const optr_from_this_const = cptr2->observer_from_this();
+
+        REQUIRE(instances == 1);
+        REQUIRE(optr_from_this.expired() == false);
+        REQUIRE(optr_from_this_const.expired() == false);
+        REQUIRE(optr_from_this.get() == ptr2.get());
+        REQUIRE(optr_from_this_const.get() == ptr2.get());
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("observer from this after move assignment", "[observer_from_this]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr_from_this ptr1{new test_object_observer_from_this};
+        test_ptr_from_this ptr2;
+        ptr2 = std::move(ptr1);
+
+        const test_ptr_from_this& cptr2 = ptr2;
+        test_optr_from_this optr_from_this = ptr2->observer_from_this();
+        test_optr_from_this_const optr_from_this_const = cptr2->observer_from_this();
+
+        REQUIRE(instances == 1);
+        REQUIRE(optr_from_this.expired() == false);
+        REQUIRE(optr_from_this_const.expired() == false);
+        REQUIRE(optr_from_this.get() == ptr2.get());
+        REQUIRE(optr_from_this_const.get() == ptr2.get());
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("observer from this after move assignment sealed", "[observer_from_this]") {
+    memory_tracker mem_track;
+
+    {
+        test_sptr_from_this ptr1 = oup::make_observable_sealed<test_object_observer_from_this>();
+        test_sptr_from_this ptr2;
+        ptr2 = std::move(ptr1);
+        const test_sptr_from_this& cptr2 = ptr2;
+
+        test_optr_from_this optr_from_this = ptr2->observer_from_this();
+        test_optr_from_this_const optr_from_this_const = cptr2->observer_from_this();
+
+        REQUIRE(instances == 1);
+        REQUIRE(optr_from_this.expired() == false);
+        REQUIRE(optr_from_this_const.expired() == false);
+        REQUIRE(optr_from_this.get() == ptr2.get());
+        REQUIRE(optr_from_this_const.get() == ptr2.get());
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("observer from this after release", "[observer_from_this]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr_from_this ptr1{new test_object_observer_from_this};
+        test_object_observer_from_this* ptr2 = ptr1.release();
+        const test_object_observer_from_this* cptr2 = ptr2;
+
+        test_optr_from_this optr_from_this = ptr2->observer_from_this();
+        test_optr_from_this_const optr_from_this_const = cptr2->observer_from_this();
+
+        REQUIRE(instances == 1);
+        REQUIRE(optr_from_this.expired() == true);
+        REQUIRE(optr_from_this_const.expired() == true);
+        REQUIRE(optr_from_this.get() == nullptr);
+        REQUIRE(optr_from_this_const.get() == nullptr);
+
+        delete ptr2;
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("observer from this after release and reset", "[observer_from_this]") {
+    memory_tracker mem_track;
+
+    {
+        test_ptr_from_this ptr1{new test_object_observer_from_this};
+        test_object_observer_from_this* ptr2 = ptr1.release();
+        const test_object_observer_from_this* cptr2 = ptr2;
+
+        test_ptr_from_this ptr3;
+        ptr3.reset(ptr2);
+
+        test_optr_from_this optr_from_this = ptr2->observer_from_this();
+        test_optr_from_this_const optr_from_this_const = cptr2->observer_from_this();
+
+        REQUIRE(instances == 1);
+        REQUIRE(optr_from_this.expired() == false);
+        REQUIRE(optr_from_this_const.expired() == false);
+        REQUIRE(optr_from_this.get() == ptr2);
+        REQUIRE(optr_from_this_const.get() == ptr2);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
+
+TEST_CASE("observer from this stack", "[observer_from_this]") {
+    memory_tracker mem_track;
+
+    {
+        test_object_observer_from_this obj;
+        const test_object_observer_from_this& cobj = obj;
+
+        test_optr_from_this optr_from_this = obj.observer_from_this();
+        test_optr_from_this_const optr_from_this_const = cobj.observer_from_this();
+
+        REQUIRE(instances == 1);
+        REQUIRE(optr_from_this.expired() == true);
+        REQUIRE(optr_from_this_const.expired() == true);
+        REQUIRE(optr_from_this.get() == nullptr);
+        REQUIRE(optr_from_this_const.get() == nullptr);
+    }
+
+    REQUIRE(instances == 0);
+    REQUIRE(mem_track.leaks() == 0u);
+    REQUIRE(mem_track.double_del() == 0u);
+}
diff --git a/tests/tests_common.hpp b/tests/tests_common.hpp
index 8dbb5f2..c8de086 100644
--- a/tests/tests_common.hpp
+++ b/tests/tests_common.hpp
@@ -38,6 +38,13 @@ struct test_object_thrower {
     test_object_thrower& operator=(test_object_thrower&&) = delete;
 };
 
+struct test_object_observer_from_this :
+    public test_object,
+    public oup::enable_observer_from_this<test_object_observer_from_this> {};
+
+struct test_object_observer_from_this_derived :
+    public test_object_observer_from_this {};
+
 struct test_deleter {
     int state_ = 0;
 
@@ -73,6 +80,14 @@ using test_ptr_derived_with_deleter = oup::observable_unique_ptr<test_object_der
 using test_ptr_thrower = oup::observable_unique_ptr<test_object_thrower>;
 using test_sptr_thrower = oup::observable_sealed_ptr<test_object_thrower>;
 using test_ptr_thrower_with_deleter = oup::observable_unique_ptr<test_object_thrower,test_deleter>;
+using test_ptr_from_this = oup::observable_unique_ptr<test_object_observer_from_this>;
+using test_sptr_from_this = oup::observable_sealed_ptr<test_object_observer_from_this>;
+using test_ptr_from_this_derived = oup::observable_unique_ptr<test_object_observer_from_this_derived>;
+using test_sptr_from_this_derived = oup::observable_sealed_ptr<test_object_observer_from_this_derived>;
 
 using test_optr = oup::observer_ptr<test_object>;
 using test_optr_derived = oup::observer_ptr<test_object_derived>;
+using test_optr_from_this = oup::observer_ptr<test_object_observer_from_this>;
+using test_optr_from_this_const = oup::observer_ptr<const test_object_observer_from_this>;
+using test_optr_from_this_derived = oup::observer_ptr<test_object_observer_from_this_derived>;
+using test_optr_from_this_derived_const = oup::observer_ptr<const test_object_observer_from_this_derived>;