diff --git a/src/xenia/kernel/xobject.cc b/src/xenia/kernel/xobject.cc
index adfc02ab4..2bff5647b 100644
--- a/src/xenia/kernel/xobject.cc
+++ b/src/xenia/kernel/xobject.cc
@@ -11,12 +11,17 @@
 
 #include <vector>
 
+#include "xenia/base/byte_stream.h"
 #include "xenia/base/clock.h"
 #include "xenia/kernel/kernel_state.h"
+#include "xenia/kernel/notify_listener.h"
 #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
+#include "xenia/kernel/xenumerator.h"
 #include "xenia/kernel/xevent.h"
+#include "xenia/kernel/xfile.h"
 #include "xenia/kernel/xmutant.h"
 #include "xenia/kernel/xsemaphore.h"
+#include "xenia/kernel/xthread.h"
 
 namespace xe {
 namespace kernel {
@@ -25,12 +30,11 @@ XObject::XObject(KernelState* kernel_state, Type type)
     : kernel_state_(kernel_state),
       pointer_ref_count_(1),
       type_(type),
-      handle_(X_INVALID_HANDLE_VALUE),
       guest_object_ptr_(0),
       allocated_guest_object_(false) {
-  // Added pointer check to support usage without a kernel_state
-  if (kernel_state != nullptr) {
-    kernel_state->object_table()->AddHandle(this, &handle_);
+  handles_.reserve(10);
+  if (kernel_state) {
+    kernel_state->object_table()->AddHandle(this, &handles_[0]);
   }
 }
 
@@ -56,15 +60,13 @@ Memory* XObject::memory() const { return kernel_state_->memory(); }
 
 XObject::Type XObject::type() { return type_; }
 
-X_HANDLE XObject::handle() const { return handle_; }
-
 void XObject::RetainHandle() {
-  kernel_state_->object_table()->RetainHandle(handle_);
+  kernel_state_->object_table()->RetainHandle(handles_[0]);
 }
 
 bool XObject::ReleaseHandle() {
   // FIXME: Return true when handle is actually released.
-  return kernel_state_->object_table()->ReleaseHandle(handle_) ==
+  return kernel_state_->object_table()->ReleaseHandle(handles_[0]) ==
          X_STATUS_SUCCESS;
 }
 
@@ -84,10 +86,70 @@ X_STATUS XObject::Delete() {
     if (!name_.empty()) {
       kernel_state_->object_table()->RemoveNameMapping(name_);
     }
-    return kernel_state_->object_table()->RemoveHandle(handle_);
+    return kernel_state_->object_table()->RemoveHandle(handles_[0]);
   }
 }
 
+bool XObject::SaveObject(ByteStream* stream) {
+  stream->Write<uint32_t>(allocated_guest_object_);
+  stream->Write<uint32_t>(guest_object_ptr_);
+
+  stream->Write(uint32_t(handles_.size()));
+  stream->Write(&handles_[0], handles_.size() * sizeof(X_HANDLE));
+
+  return true;
+}
+
+bool XObject::RestoreObject(ByteStream* stream) {
+  allocated_guest_object_ = stream->Read<uint32_t>() > 0;
+  guest_object_ptr_ = stream->Read<uint32_t>();
+
+  handles_.resize(stream->Read<uint32_t>());
+  stream->Read(&handles_[0], handles_.size() * sizeof(X_HANDLE));
+
+  // Restore our pointer to our handles in the object table.
+  for (size_t i = 0; i < handles_.size(); i++) {
+    kernel_state_->object_table()->RestoreHandle(handles_[i], this);
+  }
+
+  return true;
+}
+
+object_ref<XObject> XObject::Restore(KernelState* kernel_state, Type type,
+                                     ByteStream* stream) {
+  switch (type) {
+    case kTypeEnumerator:
+      break;
+    case kTypeEvent:
+      return XEvent::Restore(kernel_state, stream);
+    case kTypeFile:
+      break;
+    case kTypeIOCompletion:
+      break;
+    case kTypeModule:
+      break;
+    case kTypeMutant:
+      break;
+    case kTypeNotifyListener:
+      return NotifyListener::Restore(kernel_state, stream);
+    case kTypeSemaphore:
+      break;
+    case kTypeSession:
+      break;
+    case kTypeSocket:
+      break;
+    case kTypeThread:
+      return XThread::Restore(kernel_state, stream);
+    case kTypeTimer:
+      break;
+    default:
+      assert_always("No restore handler exists for this object!");
+      return nullptr;
+  }
+
+  return nullptr;
+}
+
 void XObject::SetAttributes(uint32_t obj_attributes_ptr) {
   if (!obj_attributes_ptr) {
     return;
@@ -97,7 +159,7 @@ void XObject::SetAttributes(uint32_t obj_attributes_ptr) {
                                                 obj_attributes_ptr + 4);
   if (!name.empty()) {
     name_ = std::move(name);
-    kernel_state_->object_table()->AddNameMapping(name_, handle_);
+    kernel_state_->object_table()->AddNameMapping(name_, handles_[0]);
   }
 }
 
diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h
index b5cc6d700..f16a77794 100644
--- a/src/xenia/kernel/xobject.h
+++ b/src/xenia/kernel/xobject.h
@@ -133,10 +133,22 @@ class XObject {
   Memory* memory() const;
 
   Type type();
-  X_HANDLE handle() const;
+
+  // Returns the primary handle of this object.
+  X_HANDLE handle() const { return handles_[0]; }
+
+  // Returns all associated handles with this object.
+  std::vector<X_HANDLE> handles() const { return handles_; }
+  std::vector<X_HANDLE>& handles() { return handles_; }
+
   const std::string& name() const { return name_; }
   uint32_t guest_object() const { return guest_object_ptr_; }
 
+  // Has this object been created for use by the host?
+  // Host objects are persisted through reloads/etc.
+  bool host_object() const { return host_object_; }
+  void set_host_object(bool host_object) { host_object_ = host_object; }
+
   template <typename T>
   T* guest_object() {
     return memory()->TranslateVirtual<T*>(guest_object_ptr_);
@@ -148,8 +160,9 @@ class XObject {
   void Release();
   X_STATUS Delete();
 
-  virtual bool Save(ByteStream* stream) { return false; };
-  virtual bool Restore(ByteStream* stream) { return false; };
+  virtual bool Save(ByteStream* stream) { return false; }
+  static object_ref<XObject> Restore(KernelState* kernel_state, Type type,
+                                     ByteStream* stream);
 
   // Reference()
   // Dereference()
@@ -176,6 +189,9 @@ class XObject {
   virtual xe::threading::WaitHandle* GetWaitHandle() { return nullptr; }
 
  protected:
+  bool SaveObject(ByteStream* stream);
+  bool RestoreObject(ByteStream* stream);
+
   // Creates the kernel object for guest code to use. Typically not needed.
   uint8_t* CreateNative(uint32_t size);
   void SetNativePointer(uint32_t native_ptr, bool uninitialized = false);
@@ -197,11 +213,14 @@ class XObject {
 
   KernelState* kernel_state_;
 
+  // Host objects are persisted through resets/etc.
+  bool host_object_ = false;
+
  private:
   std::atomic<int32_t> pointer_ref_count_;
 
   Type type_;
-  X_HANDLE handle_;
+  std::vector<X_HANDLE> handles_;
   std::string name_;  // May be zero length.
 
   // Guest pointer for kernel object. Remember: X_OBJECT_HEADER precedes this
@@ -292,6 +311,10 @@ class object_ref {
 
   void reset(T* value) noexcept { object_ref(value).swap(*this); }
 
+  inline bool operator==(const T* right) noexcept {
+    return value_ == right;
+  }
+
  private:
   T* value_ = nullptr;
 };