diff --git a/AK/IntrusiveRedBlackTree.h b/AK/IntrusiveRedBlackTree.h
index 6190f6b27a5..56424ec8465 100644
--- a/AK/IntrusiveRedBlackTree.h
+++ b/AK/IntrusiveRedBlackTree.h
@@ -9,17 +9,24 @@
 #include <AK/IntrusiveDetails.h>
 #include <AK/RedBlackTree.h>
 
-namespace AK {
+namespace AK::Detail {
 
-namespace Detail {
 template<Integral K, typename V, typename Container = RawPtr<V>>
 class IntrusiveRedBlackTreeNode;
-}
+
+struct ExtractIntrusiveRedBlackTreeTypes {
+    template<typename K, typename V, typename Container, typename T>
+    static K key(IntrusiveRedBlackTreeNode<K, V, Container> T::*x);
+    template<typename K, typename V, typename Container, typename T>
+    static V value(IntrusiveRedBlackTreeNode<K, V, Container> T::*x);
+    template<typename K, typename V, typename Container, typename T>
+    static Container container(IntrusiveRedBlackTreeNode<K, V, Container> T::*x);
+};
 
 template<Integral K, typename V, typename Container = RawPtr<V>>
-using IntrusiveRedBlackTreeNode = Detail::IntrusiveRedBlackTreeNode<K, V, typename Detail::SubstituteIntrusiveContainerType<V, Container>::Type>;
+using SubstitutedIntrusiveRedBlackTreeNode = IntrusiveRedBlackTreeNode<K, V, typename Detail::SubstituteIntrusiveContainerType<V, Container>::Type>;
 
-template<Integral K, typename V, typename Container, IntrusiveRedBlackTreeNode<K, V, Container> V::*member>
+template<Integral K, typename V, typename Container, SubstitutedIntrusiveRedBlackTreeNode<K, V, Container> V::*member>
 class IntrusiveRedBlackTree : public BaseRedBlackTree<K> {
 
 public:
@@ -30,7 +37,7 @@ public:
     }
 
     using BaseTree = BaseRedBlackTree<K>;
-    using TreeNode = IntrusiveRedBlackTreeNode<K, V, Container>;
+    using TreeNode = SubstitutedIntrusiveRedBlackTreeNode<K, V, Container>;
 
     Container find(K key)
     {
@@ -161,8 +168,6 @@ private:
     }
 };
 
-namespace Detail {
-
 template<Integral K, typename V, typename Container>
 class IntrusiveRedBlackTreeNode : public BaseRedBlackTree<K>::Node {
 public:
@@ -185,20 +190,18 @@ public:
 
 #ifndef __clang__
 private:
-    template<Integral TK, typename TV, typename TContainer, IntrusiveRedBlackTreeNode<TK, TV, TContainer> TV::*member>
-    friend class ::AK::IntrusiveRedBlackTree;
+    template<Integral TK, typename TV, typename TContainer, SubstitutedIntrusiveRedBlackTreeNode<TK, TV, TContainer> TV::*member>
+    friend class ::AK::Detail::IntrusiveRedBlackTree;
 #endif
 
     bool m_in_tree { false };
     [[no_unique_address]] SelfReferenceIfNeeded<Container, IsRaw> m_self;
 };
 
-}
-
 // Specialise IntrusiveRedBlackTree for NonnullRefPtr
 // By default, red black trees cannot contain null entries anyway, so switch to RefPtr
 // and just make the user-facing functions deref the pointers.
-template<Integral K, typename V, IntrusiveRedBlackTreeNode<K, V, NonnullRefPtr<V>> V::*member>
+template<Integral K, typename V, SubstitutedIntrusiveRedBlackTreeNode<K, V, NonnullRefPtr<V>> V::*member>
 class IntrusiveRedBlackTree<K, V, NonnullRefPtr<V>, member> : public IntrusiveRedBlackTree<K, V, RefPtr<V>, member> {
 public:
     [[nodiscard]] NonnullRefPtr<V> find(K key) const { return IntrusiveRedBlackTree<K, V, RefPtr<V>, member>::find(key).release_nonnull(); }
@@ -207,5 +210,19 @@ public:
 
 }
 
+namespace AK {
+
+template<Integral K, typename V, typename Container = RawPtr<K>>
+using IntrusiveRedBlackTreeNode = Detail::SubstitutedIntrusiveRedBlackTreeNode<K, V, Container>;
+
+template<auto member>
+using IntrusiveRedBlackTree = Detail::IntrusiveRedBlackTree<
+    decltype(Detail::ExtractIntrusiveRedBlackTreeTypes::key(member)),
+    decltype(Detail::ExtractIntrusiveRedBlackTreeTypes::value(member)),
+    decltype(Detail::ExtractIntrusiveRedBlackTreeTypes::container(member)),
+    member>;
+
+}
+
 using AK::IntrusiveRedBlackTree;
 using AK::IntrusiveRedBlackTreeNode;
diff --git a/Kernel/Memory/PageDirectory.cpp b/Kernel/Memory/PageDirectory.cpp
index 133bfc91651..e277e634547 100644
--- a/Kernel/Memory/PageDirectory.cpp
+++ b/Kernel/Memory/PageDirectory.cpp
@@ -17,9 +17,9 @@ extern u8 end_of_kernel_image[];
 
 namespace Kernel::Memory {
 
-static Singleton<IntrusiveRedBlackTree<FlatPtr, PageDirectory, RawPtr<PageDirectory>, &PageDirectory::m_tree_node>> s_cr3_map;
+static Singleton<IntrusiveRedBlackTree<&PageDirectory::m_tree_node>> s_cr3_map;
 
-static IntrusiveRedBlackTree<FlatPtr, PageDirectory, RawPtr<PageDirectory>, &PageDirectory::m_tree_node>& cr3_map()
+static IntrusiveRedBlackTree<&PageDirectory::m_tree_node>& cr3_map()
 {
     VERIFY_INTERRUPTS_DISABLED();
     return *s_cr3_map;
diff --git a/Tests/AK/TestIntrusiveRedBlackTree.cpp b/Tests/AK/TestIntrusiveRedBlackTree.cpp
index a27e8abb186..6492c577704 100644
--- a/Tests/AK/TestIntrusiveRedBlackTree.cpp
+++ b/Tests/AK/TestIntrusiveRedBlackTree.cpp
@@ -20,7 +20,7 @@ public:
     IntrusiveRedBlackTreeNode<int, IntrusiveTest, RawPtr<IntrusiveTest>> m_tree_node;
     int m_some_value;
 };
-using IntrusiveRBTree = IntrusiveRedBlackTree<int, IntrusiveTest, RawPtr<IntrusiveTest>, &IntrusiveTest::m_tree_node>;
+using IntrusiveRBTree = IntrusiveRedBlackTree<&IntrusiveTest::m_tree_node>;
 
 TEST_CASE(construct)
 {
@@ -123,7 +123,7 @@ public:
 
     IntrusiveRedBlackTreeNode<int, IntrusiveRefPtrTest, RefPtr<IntrusiveRefPtrTest>> m_tree_node;
 };
-using IntrusiveRefPtrRBTree = IntrusiveRedBlackTree<int, IntrusiveRefPtrTest, RefPtr<IntrusiveRefPtrTest>, &IntrusiveRefPtrTest::m_tree_node>;
+using IntrusiveRefPtrRBTree = IntrusiveRedBlackTree<&IntrusiveRefPtrTest::m_tree_node>;
 
 TEST_CASE(intrusive_ref_ptr_no_ref_leaks)
 {
@@ -173,7 +173,7 @@ public:
 
     IntrusiveRedBlackTreeNode<int, IntrusiveNonnullRefPtrTest, NonnullRefPtr<IntrusiveNonnullRefPtrTest>> m_tree_node;
 };
-using IntrusiveNonnullRefPtrRBTree = IntrusiveRedBlackTree<int, IntrusiveNonnullRefPtrTest, NonnullRefPtr<IntrusiveNonnullRefPtrTest>, &IntrusiveNonnullRefPtrTest::m_tree_node>;
+using IntrusiveNonnullRefPtrRBTree = IntrusiveRedBlackTree<&IntrusiveNonnullRefPtrTest::m_tree_node>;
 
 TEST_CASE(intrusive_nonnull_ref_ptr_intrusive)
 {