diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index e0f53287cb..5d0b266c59 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -62,7 +62,7 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context,
 namespace Kernel {
 
 KThread::KThread(KernelCore& kernel)
-    : KSynchronizationObject{kernel}, activity_pause_lock{kernel} {}
+    : KAutoObjectWithSlabHeapAndContainer{kernel}, activity_pause_lock{kernel} {}
 KThread::~KThread() = default;
 
 ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio,
@@ -177,6 +177,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
     // Set parent, if relevant.
     if (owner != nullptr) {
         parent = owner;
+        parent->Open();
         parent->IncrementThreadCount();
     }
 
@@ -210,13 +211,55 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
 
 ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg,
                                      VAddr user_stack_top, s32 prio, s32 core, Process* owner,
-                                     ThreadType type) {
+                                     ThreadType type, std::function<void(void*)>&& init_func,
+                                     void* init_func_parameter) {
     // Initialize the thread.
     R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type));
 
+    // Initialize host context.
+    thread->host_context =
+        std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter);
+
     return RESULT_SUCCESS;
 }
 
+ResultCode KThread::InitializeDummyThread(KThread* thread) {
+    return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Main);
+}
+
+ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
+    return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main,
+                            Core::CpuManager::GetIdleThreadStartFunc(),
+                            system.GetCpuManager().GetStartFuncParamater());
+}
+
+ResultCode KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread,
+                                                 KThreadFunction func, uintptr_t arg,
+                                                 s32 virt_core) {
+    return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority,
+                            Core::CpuManager::GetSuspendThreadStartFunc(),
+                            system.GetCpuManager().GetStartFuncParamater());
+}
+
+ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread,
+                                         KThreadFunction func, uintptr_t arg, VAddr user_stack_top,
+                                         s32 prio, s32 virt_core, Process* owner) {
+    system.Kernel().GlobalSchedulerContext().AddThread(thread);
+    return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
+                            ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(),
+                            system.GetCpuManager().GetStartFuncParamater());
+}
+
+void KThread::PostDestroy(uintptr_t arg) {
+    Process* owner = reinterpret_cast<Process*>(arg & ~1ULL);
+    const bool resource_limit_release_hint = (arg & 1);
+    const s64 hint_value = (resource_limit_release_hint ? 0 : 1);
+    if (owner != nullptr) {
+        owner->GetResourceLimit()->Release(Kernel::LimitableResource::Threads, 1, hint_value);
+        owner->Close();
+    }
+}
+
 void KThread::Finalize() {
     // If the thread has an owner process, unregister it.
     if (parent != nullptr) {
@@ -294,6 +337,9 @@ void KThread::StartTermination() {
 
     // Register terminated dpc flag.
     RegisterDpc(DpcFlag::Terminated);
+
+    // Close the thread.
+    this->Close();
 }
 
 void KThread::Pin() {
@@ -995,56 +1041,6 @@ std::shared_ptr<Common::Fiber>& KThread::GetHostContext() {
     return host_context;
 }
 
-ResultVal<std::shared_ptr<KThread>> KThread::CreateThread(Core::System& system,
-                                                          ThreadType type_flags, std::string name,
-                                                          VAddr entry_point, u32 priority, u64 arg,
-                                                          s32 processor_id, VAddr stack_top,
-                                                          Process* owner_process) {
-    auto& kernel = system.Kernel();
-
-    std::shared_ptr<KThread> thread = std::make_shared<KThread>(kernel);
-
-    if (const auto result =
-            thread->InitializeThread(thread.get(), entry_point, arg, stack_top, priority,
-                                     processor_id, owner_process, type_flags);
-        result.IsError()) {
-        return result;
-    }
-
-    thread->name = name;
-
-    auto& scheduler = kernel.GlobalSchedulerContext();
-    scheduler.AddThread(thread);
-
-    return MakeResult<std::shared_ptr<KThread>>(std::move(thread));
-}
-
-ResultVal<std::shared_ptr<KThread>> KThread::CreateThread(
-    Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority,
-    u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process,
-    std::function<void(void*)>&& thread_start_func, void* thread_start_parameter) {
-    auto thread_result = CreateThread(system, type_flags, name, entry_point, priority, arg,
-                                      processor_id, stack_top, owner_process);
-
-    if (thread_result.Succeeded()) {
-        (*thread_result)->host_context =
-            std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter);
-    }
-
-    return thread_result;
-}
-
-ResultVal<std::shared_ptr<KThread>> KThread::CreateUserThread(
-    Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority,
-    u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process) {
-    std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc();
-
-    void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
-
-    return CreateThread(system, type_flags, name, entry_point, priority, arg, processor_id,
-                        stack_top, owner_process, std::move(init_func), init_func_parameter);
-}
-
 KThread* GetCurrentThreadPointer(KernelCore& kernel) {
     return kernel.GetCurrentEmuThread();
 }
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index b442dfe577..5c1c17d486 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -20,6 +20,7 @@
 #include "core/hle/kernel/k_spin_lock.h"
 #include "core/hle/kernel/k_synchronization_object.h"
 #include "core/hle/kernel/object.h"
+#include "core/hle/kernel/slab_helpers.h"
 #include "core/hle/kernel/svc_common.h"
 #include "core/hle/kernel/svc_types.h"
 #include "core/hle/result.h"
@@ -99,7 +100,11 @@ enum class ThreadWaitReasonForDebugging : u32 {
 [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel);
 [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel);
 
-class KThread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> {
+class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>,
+                      public boost::intrusive::list_base_hook<> {
+    KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject);
+
+private:
     friend class KScheduler;
     friend class Process;
 
@@ -115,57 +120,6 @@ public:
     using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
     using WaiterList = boost::intrusive::list<KThread>;
 
-    /**
-     * Creates and returns a new thread.
-     * @param system The instance of the whole system
-     * @param name The friendly name desired for the thread
-     * @param entry_point The address at which the thread should start execution
-     * @param priority The thread's priority
-     * @param arg User data to pass to the thread
-     * @param processor_id The ID(s) of the processors on which the thread is desired to be run
-     * @param stack_top The address of the thread's stack top
-     * @param owner_process The parent process for the thread, if null, it's a kernel thread
-     * @return A shared pointer to the newly created thread
-     */
-    [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread(
-        Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
-        u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process);
-
-    /**
-     * Creates and returns a new thread, with a specified entry point.
-     * @param system The instance of the whole system
-     * @param name The friendly name desired for the thread
-     * @param entry_point The address at which the thread should start execution
-     * @param priority The thread's priority
-     * @param arg User data to pass to the thread
-     * @param processor_id The ID(s) of the processors on which the thread is desired to be run
-     * @param stack_top The address of the thread's stack top
-     * @param owner_process The parent process for the thread, if null, it's a kernel thread
-     * @param thread_start_func The function where the host context will start.
-     * @param thread_start_parameter The parameter which will passed to host context on init
-     * @return A shared pointer to the newly created thread
-     */
-    [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread(
-        Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
-        u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process,
-        std::function<void(void*)>&& thread_start_func, void* thread_start_parameter);
-
-    /**
-     * Creates and returns a new thread for the emulated "user" process.
-     * @param system The instance of the whole system
-     * @param name The friendly name desired for the thread
-     * @param entry_point The address at which the thread should start execution
-     * @param priority The thread's priority
-     * @param arg User data to pass to the thread
-     * @param processor_id The ID(s) of the processors on which the thread is desired to be run
-     * @param stack_top The address of the thread's stack top
-     * @param owner_process The parent process for the thread, if null, it's a kernel thread
-     * @return A shared pointer to the newly created thread
-     */
-    [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateUserThread(
-        Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
-        u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process);
-
     [[nodiscard]] std::string GetName() const override {
         return name;
     }
@@ -257,10 +211,6 @@ public:
 
     void Suspend();
 
-    void Finalize() override;
-
-    bool IsSignaled() const override;
-
     void SetSyncedObject(KSynchronizationObject* obj, ResultCode wait_res) {
         synced_object = obj;
         wait_result = wait_res;
@@ -422,6 +372,40 @@ public:
         return termination_requested || GetRawState() == ThreadState::Terminated;
     }
 
+    [[nodiscard]] virtual u64 GetId() const override final {
+        return this->GetThreadID();
+    }
+
+    [[nodiscard]] virtual bool IsInitialized() const override {
+        return initialized;
+    }
+
+    [[nodiscard]] virtual uintptr_t GetPostDestroyArgument() const override {
+        return reinterpret_cast<uintptr_t>(parent) | (resource_limit_release_hint ? 1 : 0);
+    }
+
+    virtual void Finalize() override;
+
+    [[nodiscard]] virtual bool IsSignaled() const override;
+
+    static void PostDestroy(uintptr_t arg);
+
+    [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread);
+
+    [[nodiscard]] static ResultCode InitializeIdleThread(Core::System& system, KThread* thread,
+                                                         s32 virt_core);
+
+    [[nodiscard]] static ResultCode InitializeHighPriorityThread(Core::System& system,
+                                                                 KThread* thread,
+                                                                 KThreadFunction func,
+                                                                 uintptr_t arg, s32 virt_core);
+
+    [[nodiscard]] static ResultCode InitializeUserThread(Core::System& system, KThread* thread,
+                                                         KThreadFunction func, uintptr_t arg,
+                                                         VAddr user_stack_top, s32 prio,
+                                                         s32 virt_core, Process* owner);
+
+public:
     struct StackParameters {
         u8 svc_permission[0x10];
         std::atomic<u8> dpc_flags;
@@ -675,7 +659,9 @@ private:
 
     [[nodiscard]] static ResultCode InitializeThread(KThread* thread, KThreadFunction func,
                                                      uintptr_t arg, VAddr user_stack_top, s32 prio,
-                                                     s32 core, Process* owner, ThreadType type);
+                                                     s32 core, Process* owner, ThreadType type,
+                                                     std::function<void(void*)>&& init_func,
+                                                     void* init_func_parameter);
 
     static void RestorePriority(KernelCore& kernel, KThread* thread);