Index: kernel/generic/include/cap/cap.h
===================================================================
--- kernel/generic/include/cap/cap.h	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/include/cap/cap.h	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -37,11 +37,12 @@
 
 #include <abi/cap.h>
+#include <adt/hash_table.h>
+#include <adt/hash.h>
+#include <adt/list.h>
+#include <atomic.h>
+#include <lib/ra.h>
+#include <lib/refcount.h>
+#include <synch/mutex.h>
 #include <typedefs.h>
-#include <adt/list.h>
-#include <adt/hash.h>
-#include <adt/hash_table.h>
-#include <lib/ra.h>
-#include <synch/mutex.h>
-#include <atomic.h>
 
 typedef enum {
@@ -59,13 +60,8 @@
 } kobject_type_t;
 
-struct task;
-
-struct call;
-struct irq;
-struct phone;
-struct waitq;
+struct kobject;
 
 typedef struct kobject_ops {
-	void (*destroy)(void *);
+	void (*destroy)(struct kobject *);
 } kobject_ops_t;
 
@@ -76,9 +72,9 @@
 /*
  * Everything in kobject_t except for the atomic reference count, the capability
- * list and its lock is imutable.
+ * list and its lock is immutable.
  */
 typedef struct kobject {
 	kobject_type_t type;
-	atomic_size_t refcnt;
+	atomic_refcount_t refcnt;
 
 	/** Mutex protecting caps_list */
@@ -86,12 +82,4 @@
 	/** List of published capabilities associated with the kobject */
 	list_t caps_list;
-
-	union {
-		void *raw;
-		struct call *call;
-		struct irq *irq;
-		struct phone *phone;
-		struct waitq *waitq;
-	};
 } kobject_t;
 
@@ -129,5 +117,6 @@
 extern errno_t caps_task_alloc(struct task *);
 extern void caps_task_free(struct task *);
-extern void caps_task_init(struct task *);
+extern void caps_task_clear(struct task *task);
+extern errno_t caps_task_init(struct task *);
 extern bool caps_apply_to_kobject_type(struct task *, kobject_type_t,
     bool (*)(cap_t *, void *), void *);
@@ -139,7 +128,5 @@
 extern void cap_free(struct task *, cap_handle_t);
 
-extern kobject_t *kobject_alloc(unsigned int);
-extern void kobject_free(kobject_t *);
-extern void kobject_initialize(kobject_t *, kobject_type_t, void *);
+extern void kobject_initialize(kobject_t *, kobject_type_t);
 extern kobject_t *kobject_get(struct task *, cap_handle_t, kobject_type_t);
 extern void kobject_add_ref(kobject_t *);
Index: kernel/generic/include/ddi/irq.h
===================================================================
--- kernel/generic/include/ddi/irq.h	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/include/ddi/irq.h	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -132,6 +132,4 @@
 extern hash_table_t irq_uspace_hash_table;
 
-extern slab_cache_t *irq_cache;
-
 extern inr_t last_inr;
 
Index: kernel/generic/include/ipc/ipc.h
===================================================================
--- kernel/generic/include/ipc/ipc.h	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/include/ipc/ipc.h	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -74,5 +74,5 @@
 	/** User-defined label */
 	sysarg_t label;
-	kobject_t *kobject;
+	kobject_t kobject;
 } phone_t;
 
@@ -108,5 +108,5 @@
 
 typedef struct call {
-	kobject_t *kobject;
+	kobject_t kobject;
 
 	/**
@@ -169,8 +169,25 @@
 
 extern slab_cache_t *phone_cache;
+extern slab_cache_t *irq_cache;
 
 extern answerbox_t *ipc_box_0;
 
 extern kobject_ops_t call_kobject_ops;
+
+static inline phone_t *phone_from_kobject(kobject_t *kobject)
+{
+	if (kobject)
+		return ((void *) kobject) - offsetof(phone_t, kobject);
+	else
+		return NULL;
+}
+
+static inline call_t *call_from_kobject(kobject_t *kobject)
+{
+	if (kobject)
+		return ((void *) kobject) - offsetof(call_t, kobject);
+	else
+		return NULL;
+}
 
 extern void ipc_init(void);
Index: kernel/generic/include/ipc/irq.h
===================================================================
--- kernel/generic/include/ipc/irq.h	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/include/ipc/irq.h	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -50,4 +50,18 @@
 extern kobject_ops_t irq_kobject_ops;
 
+typedef struct {
+	kobject_t kobject;
+	irq_t irq;
+} irq_kobject_t;
+
+static inline irq_t *irq_from_kobject(kobject_t *kobject)
+{
+	if (kobject) {
+		return &((irq_kobject_t *) kobject)->irq;
+	} else {
+		return NULL;
+	}
+}
+
 extern irq_ownership_t ipc_irq_top_half_claim(irq_t *);
 extern void ipc_irq_top_half_handler(irq_t *);
Index: kernel/generic/include/synch/syswaitq.h
===================================================================
--- kernel/generic/include/synch/syswaitq.h	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/include/synch/syswaitq.h	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -44,6 +44,4 @@
 extern void sys_waitq_init(void);
 
-extern void sys_waitq_task_cleanup(void);
-
 extern sys_errno_t sys_waitq_create(uspace_ptr_cap_waitq_handle_t);
 extern sys_errno_t sys_waitq_sleep(cap_waitq_handle_t, uint32_t, unsigned int);
Index: kernel/generic/src/cap/cap.c
===================================================================
--- kernel/generic/src/cap/cap.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/cap/cap.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -93,9 +93,8 @@
 
 #define CAPS_START	((intptr_t) CAP_NIL + 1)
-#define CAPS_SIZE	(INT_MAX - (int) CAPS_START)
-#define CAPS_LAST	(CAPS_SIZE - 1)
+#define CAPS_LAST	((intptr_t) INT_MAX - 1)
+#define CAPS_SIZE	(CAPS_LAST - CAPS_START + 1)
 
 static slab_cache_t *cap_cache;
-static slab_cache_t *kobject_cache;
 
 kobject_ops_t *kobject_ops[KOBJECT_TYPE_MAX] = {
@@ -125,8 +124,29 @@
 }
 
+static void caps_remove_callback(ht_link_t *item)
+{
+	cap_t *cap = hash_table_get_inst(item, cap_t, caps_link);
+
+	if (cap->kobject) {
+		kobject_t *kobj = cap->kobject;
+
+		mutex_lock(&kobj->caps_list_lock);
+		cap->kobject = NULL;
+		list_remove(&cap->kobj_link);
+		mutex_unlock(&kobj->caps_list_lock);
+
+		kobject_put(kobj);
+	}
+
+	list_remove(&cap->type_link);
+
+	slab_free(cap_cache, cap);
+}
+
 static const hash_table_ops_t caps_ops = {
 	.hash = caps_hash,
 	.key_hash = caps_key_hash,
-	.key_equal = caps_key_equal
+	.key_equal = caps_key_equal,
+	.remove_callback = caps_remove_callback,
 };
 
@@ -135,6 +155,4 @@
 	cap_cache = slab_cache_create("cap_t", sizeof(cap_t), 0, NULL,
 	    NULL, 0);
-	kobject_cache = slab_cache_create("kobject_t", sizeof(kobject_t), 0,
-	    NULL, NULL, 0);
 }
 
@@ -148,30 +166,56 @@
 	if (!task->cap_info)
 		return ENOMEM;
+
+	if (!hash_table_create(&task->cap_info->caps, 0, 0, &caps_ops)) {
+		free(task->cap_info);
+		return ENOMEM;
+	}
+
+	mutex_initialize(&task->cap_info->lock, MUTEX_RECURSIVE);
+
+	task->cap_info->handles = NULL;
+
+	for (kobject_type_t t = 0; t < KOBJECT_TYPE_MAX; t++)
+		list_initialize(&task->cap_info->type_list[t]);
+
+	return EOK;
+}
+
+/** Initialize the capability info structure
+ *
+ * @param task  Task for which to initialize the info structure.
+ */
+errno_t caps_task_init(task_t *task)
+{
+	assert(task->cap_info);
+	assert(!task->cap_info->handles);
+
 	task->cap_info->handles = ra_arena_create();
 	if (!task->cap_info->handles)
-		goto error_handles;
-	if (!ra_span_add(task->cap_info->handles, CAPS_START, CAPS_SIZE))
-		goto error_span;
-	if (!hash_table_create(&task->cap_info->caps, 0, 0, &caps_ops))
-		goto error_span;
+		return ENOMEM;
+
+	if (!ra_span_add(task->cap_info->handles, CAPS_START, CAPS_SIZE)) {
+		ra_arena_destroy(task->cap_info->handles);
+		return ENOMEM;
+	}
+
 	return EOK;
-
-error_span:
-	ra_arena_destroy(task->cap_info->handles);
-error_handles:
-	free(task->cap_info);
-	return ENOMEM;
-}
-
-/** Initialize the capability info structure
- *
- * @param task  Task for which to initialize the info structure.
- */
-void caps_task_init(task_t *task)
-{
-	mutex_initialize(&task->cap_info->lock, MUTEX_RECURSIVE);
+}
+
+void caps_task_clear(task_t *task)
+{
+	mutex_lock(&task->cap_info->lock);
+
+	hash_table_clear(&task->cap_info->caps);
+
+	if (task->cap_info->handles) {
+		ra_arena_destroy(task->cap_info->handles);
+		task->cap_info->handles = NULL;
+	}
 
 	for (kobject_type_t t = 0; t < KOBJECT_TYPE_MAX; t++)
 		list_initialize(&task->cap_info->type_list[t]);
+
+	mutex_unlock(&task->cap_info->lock);
 }
 
@@ -183,5 +227,8 @@
 {
 	hash_table_destroy(&task->cap_info->caps);
-	ra_arena_destroy(task->cap_info->handles);
+
+	if (task->cap_info->handles)
+		ra_arena_destroy(task->cap_info->handles);
+
 	free(task->cap_info);
 }
@@ -300,6 +347,6 @@
 cap_publish(task_t *task, cap_handle_t handle, kobject_t *kobj)
 {
+	mutex_lock(&task->cap_info->lock);
 	mutex_lock(&kobj->caps_list_lock);
-	mutex_lock(&task->cap_info->lock);
 	cap_t *cap = cap_get(task, handle, CAP_STATE_ALLOCATED);
 	assert(cap);
@@ -309,6 +356,6 @@
 	list_append(&cap->kobj_link, &kobj->caps_list);
 	list_append(&cap->type_link, &task->cap_info->type_list[kobj->type]);
-	mutex_unlock(&task->cap_info->lock);
 	mutex_unlock(&kobj->caps_list_lock);
+	mutex_unlock(&task->cap_info->lock);
 }
 
@@ -340,5 +387,4 @@
 	kobject_t *kobj = NULL;
 
-restart:
 	mutex_lock(&task->cap_info->lock);
 	cap_t *cap = cap_get(task, handle, CAP_STATE_PUBLISHED);
@@ -347,9 +393,6 @@
 			/* Hand over cap's reference to kobj */
 			kobj = cap->kobject;
-			if (mutex_trylock(&kobj->caps_list_lock) != EOK) {
-				mutex_unlock(&task->cap_info->lock);
-				kobj = NULL;
-				goto restart;
-			}
+
+			mutex_lock(&kobj->caps_list_lock);
 			cap_unpublish_unsafe(cap);
 			mutex_unlock(&kobj->caps_list_lock);
@@ -376,12 +419,22 @@
 {
 	mutex_lock(&kobj->caps_list_lock);
-	list_foreach_safe(kobj->caps_list, cur, hlp) {
-		cap_t *cap = list_get_instance(cur, cap_t, kobj_link);
-		mutex_lock(&cap->task->cap_info->lock);
+
+	while (!list_empty(&kobj->caps_list)) {
+		cap_t *cap = list_get_instance(list_first(&kobj->caps_list), cap_t, kobj_link);
+
+		/* We're trying to acquire the two locks in reverse order. */
+		if (mutex_trylock(&cap->task->cap_info->lock) != EOK) {
+			mutex_unlock(&kobj->caps_list_lock);
+			mutex_lock(&kobj->caps_list_lock);
+			continue;
+		}
+
 		cap_unpublish_unsafe(cap);
 		/* Drop the reference for the unpublished capability */
 		kobject_put(kobj);
+
 		mutex_unlock(&cap->task->cap_info->lock);
 	}
+
 	mutex_unlock(&kobj->caps_list_lock);
 }
@@ -404,16 +457,5 @@
 	hash_table_remove_item(&task->cap_info->caps, &cap->caps_link);
 	ra_free(task->cap_info->handles, cap_handle_raw(handle), 1);
-	slab_free(cap_cache, cap);
-	mutex_unlock(&task->cap_info->lock);
-}
-
-kobject_t *kobject_alloc(unsigned int flags)
-{
-	return slab_alloc(kobject_cache, flags);
-}
-
-void kobject_free(kobject_t *kobj)
-{
-	slab_free(kobject_cache, kobj);
+	mutex_unlock(&task->cap_info->lock);
 }
 
@@ -422,9 +464,8 @@
  * @param kobj  Kernel object to initialize.
  * @param type  Type of the kernel object.
- * @param raw   Raw pointer to the encapsulated object.
- */
-void kobject_initialize(kobject_t *kobj, kobject_type_t type, void *raw)
-{
-	atomic_store(&kobj->refcnt, 1);
+ */
+void kobject_initialize(kobject_t *kobj, kobject_type_t type)
+{
+	refcount_init(&kobj->refcnt);
 
 	mutex_initialize(&kobj->caps_list_lock, MUTEX_PASSIVE);
@@ -432,5 +473,4 @@
 
 	kobj->type = type;
-	kobj->raw = raw;
 }
 
@@ -455,5 +495,5 @@
 		if (cap->kobject->type == type) {
 			kobj = cap->kobject;
-			atomic_inc(&kobj->refcnt);
+			refcount_up(&kobj->refcnt);
 		}
 	}
@@ -469,5 +509,5 @@
 void kobject_add_ref(kobject_t *kobj)
 {
-	atomic_inc(&kobj->refcnt);
+	refcount_up(&kobj->refcnt);
 }
 
@@ -481,7 +521,6 @@
 void kobject_put(kobject_t *kobj)
 {
-	if (atomic_postdec(&kobj->refcnt) == 1) {
-		KOBJECT_OP(kobj)->destroy(kobj->raw);
-		kobject_free(kobj);
+	if (refcount_down(&kobj->refcnt)) {
+		KOBJECT_OP(kobj)->destroy(kobj);
 	}
 }
Index: kernel/generic/src/ddi/irq.c
===================================================================
--- kernel/generic/src/ddi/irq.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/ddi/irq.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -50,6 +50,4 @@
 #include <arch.h>
 
-slab_cache_t *irq_cache = NULL;
-
 /** Spinlock protecting the kernel IRQ hash table
  *
@@ -96,8 +94,4 @@
 {
 	last_inr = inrs - 1;
-
-	irq_cache = slab_cache_create("irq_t", sizeof(irq_t), 0, NULL, NULL,
-	    FRAME_ATOMIC);
-	assert(irq_cache);
 
 	hash_table_create(&irq_uspace_hash_table, chains, 0, &irq_ht_ops);
Index: kernel/generic/src/ipc/ipc.c
===================================================================
--- kernel/generic/src/ipc/ipc.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/ipc/ipc.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -71,4 +71,5 @@
 static slab_cache_t *answerbox_cache;
 
+slab_cache_t *irq_cache = NULL;
 slab_cache_t *phone_cache = NULL;
 
@@ -87,14 +88,15 @@
 	call->callerbox = NULL;
 	call->buffer = NULL;
-}
-
-static void call_destroy(void *arg)
-{
-	call_t *call = (call_t *) arg;
+	kobject_initialize(&call->kobject, KOBJECT_TYPE_CALL);
+}
+
+static void call_destroy(kobject_t *arg)
+{
+	call_t *call = call_from_kobject(arg);
 
 	if (call->buffer)
 		free(call->buffer);
 	if (call->caller_phone)
-		kobject_put(call->caller_phone->kobject);
+		kobject_put(&call->caller_phone->kobject);
 	slab_free(call_cache, call);
 }
@@ -114,19 +116,9 @@
 call_t *ipc_call_alloc(void)
 {
-	// TODO: Allocate call and kobject in single allocation
-
 	call_t *call = slab_alloc(call_cache, FRAME_ATOMIC);
 	if (!call)
 		return NULL;
 
-	kobject_t *kobj = kobject_alloc(0);
-	if (!kobj) {
-		slab_free(call_cache, call);
-		return NULL;
-	}
-
 	_ipc_call_init(call);
-	kobject_initialize(kobj, KOBJECT_TYPE_CALL, call);
-	call->kobject = kobj;
 
 	return call;
@@ -181,5 +173,5 @@
 	if (!connected) {
 		/* We still have phone->kobject's reference; drop it */
-		kobject_put(phone->kobject);
+		kobject_put(&phone->kobject);
 	}
 
@@ -201,5 +193,5 @@
 	atomic_store(&phone->active_calls, 0);
 	phone->label = 0;
-	phone->kobject = NULL;
+	kobject_initialize(&phone->kobject, KOBJECT_TYPE_PHONE);
 }
 
@@ -294,5 +286,5 @@
 		/* This is a forgotten call and call->sender is not valid. */
 		spinlock_unlock(&call->forget_lock);
-		kobject_put(call->kobject);
+		kobject_put(&call->kobject);
 		return;
 	} else {
@@ -352,5 +344,5 @@
 
 	call->caller_phone = phone;
-	kobject_add_ref(phone->kobject);
+	kobject_add_ref(&phone->kobject);
 
 	if (preforget) {
@@ -362,5 +354,5 @@
 		else
 			atomic_inc(&caller->answerbox.active_calls);
-		kobject_add_ref(phone->kobject);
+		kobject_add_ref(&phone->kobject);
 		call->sender = caller;
 		call->active = true;
@@ -479,5 +471,5 @@
 
 		/* Drop the answerbox reference */
-		kobject_put(phone->kobject);
+		kobject_put(&phone->kobject);
 
 		call_t *call = phone->hangup_call;
@@ -581,5 +573,5 @@
 		atomic_dec(&request->caller_phone->active_calls);
 		atomic_dec(&box->active_calls);
-		kobject_put(request->caller_phone->kobject);
+		kobject_put(&request->caller_phone->kobject);
 	} else if (!list_empty(&box->calls)) {
 		/* Count received call */
@@ -697,5 +689,5 @@
 			task_release(phone->caller);
 
-			kobject_put(phone->kobject);
+			kobject_put(&phone->kobject);
 
 			/* Must start again */
@@ -704,5 +696,5 @@
 
 		mutex_unlock(&phone->lock);
-		kobject_put(phone->kobject);
+		kobject_put(&phone->kobject);
 	}
 
@@ -728,5 +720,5 @@
 	 * must hold a reference to it.
 	 */
-	kobject_add_ref(call->kobject);
+	kobject_add_ref(&call->kobject);
 
 	spinlock_unlock(&call->forget_lock);
@@ -735,9 +727,9 @@
 	atomic_dec(&call->caller_phone->active_calls);
 	atomic_dec(&TASK->answerbox.active_calls);
-	kobject_put(call->caller_phone->kobject);
+	kobject_put(&call->caller_phone->kobject);
 
 	SYSIPC_OP(request_forget, call);
 
-	kobject_put(call->kobject);
+	kobject_put(&call->kobject);
 }
 
@@ -777,5 +769,5 @@
 static bool phone_cap_cleanup_cb(cap_t *cap, void *arg)
 {
-	ipc_phone_hangup(cap->kobject->phone);
+	ipc_phone_hangup(phone_from_kobject(cap->kobject));
 	kobject_t *kobj = cap_unpublish(cap->task, cap->handle,
 	    KOBJECT_TYPE_PHONE);
@@ -798,5 +790,5 @@
 		SYSIPC_OP(answer_process, call);
 
-		kobject_put(call->kobject);
+		kobject_put(&call->kobject);
 
 		/*
@@ -892,4 +884,6 @@
 	answerbox_cache = slab_cache_create("answerbox_t", sizeof(answerbox_t),
 	    0, NULL, NULL, 0);
+	irq_cache = slab_cache_create("irq_t", sizeof(irq_kobject_t),
+	    0, NULL, NULL, 0);
 }
 
@@ -927,5 +921,5 @@
 static bool print_task_phone_cb(cap_t *cap, void *arg)
 {
-	phone_t *phone = cap->kobject->phone;
+	phone_t *phone = phone_from_kobject(cap->kobject);
 
 	mutex_lock(&phone->lock);
Index: kernel/generic/src/ipc/ipcrsc.c
===================================================================
--- kernel/generic/src/ipc/ipcrsc.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/ipc/ipcrsc.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -44,9 +44,9 @@
 #include <stdlib.h>
 
-static void phone_destroy(void *arg)
+static void phone_destroy(kobject_t *arg)
 {
-	phone_t *phone = (phone_t *) arg;
+	phone_t *phone = phone_from_kobject(arg);
 	if (phone->hangup_call)
-		kobject_put(phone->hangup_call->kobject);
+		kobject_put(&phone->hangup_call->kobject);
 	slab_free(phone_cache, phone);
 }
@@ -76,15 +76,9 @@
 			return ENOMEM;
 		}
-		kobject_t *kobj = kobject_alloc(FRAME_ATOMIC);
-		if (!kobj) {
-			cap_free(TASK, handle);
-			slab_free(phone_cache, phone);
-			return ENOMEM;
-		}
+
 		call_t *hcall = ipc_call_alloc();
 		if (!hcall) {
 			cap_free(TASK, handle);
 			slab_free(phone_cache, phone);
-			free(kobj);
 			return ENOMEM;
 		}
@@ -94,13 +88,10 @@
 		phone->hangup_call = hcall;
 
-		kobject_initialize(kobj, KOBJECT_TYPE_PHONE, phone);
-		phone->kobject = kobj;
-
 		if (publish)
-			cap_publish(task, handle, kobj);
+			cap_publish(task, handle, &phone->kobject);
 
 		*phandle = handle;
 		if (kobject)
-			*kobject = kobj;
+			*kobject = &phone->kobject;
 	}
 	return rc;
Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/ipc/irq.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -295,13 +295,13 @@
 }
 
-static void irq_destroy(void *arg)
-{
-	irq_t *irq = (irq_t *) arg;
-
-	irq_hash_out(irq);
+static void irq_destroy(kobject_t *arg)
+{
+	irq_kobject_t *kobj = (irq_kobject_t *) arg;
+
+	irq_hash_out(&kobj->irq);
 
 	/* Free up the IRQ code and associated structures. */
-	code_free(irq->notif_cfg.code);
-	slab_free(irq_cache, irq);
+	code_free(kobj->irq.notif_cfg.code);
+	slab_free(irq_cache, kobj);
 }
 
@@ -350,16 +350,13 @@
 	}
 
-	irq_t *irq = (irq_t *) slab_alloc(irq_cache, FRAME_ATOMIC);
-	if (!irq) {
+	irq_kobject_t *kobj = slab_alloc(irq_cache, FRAME_ATOMIC);
+	if (!kobj) {
 		cap_free(TASK, handle);
 		return ENOMEM;
 	}
 
-	kobject_t *kobject = kobject_alloc(FRAME_ATOMIC);
-	if (!kobject) {
-		cap_free(TASK, handle);
-		slab_free(irq_cache, irq);
-		return ENOMEM;
-	}
+	kobject_initialize(&kobj->kobject, KOBJECT_TYPE_IRQ);
+
+	irq_t *irq = &kobj->irq;
 
 	irq_initialize(irq);
@@ -385,6 +382,5 @@
 	irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
 
-	kobject_initialize(kobject, KOBJECT_TYPE_IRQ, irq);
-	cap_publish(TASK, handle, kobject);
+	cap_publish(TASK, handle, &kobj->kobject);
 
 	return EOK;
@@ -405,7 +401,7 @@
 		return ENOENT;
 
-	assert(kobj->irq->notif_cfg.answerbox == box);
-
-	irq_hash_out(kobj->irq);
+	assert(irq_from_kobject(kobj)->notif_cfg.answerbox == box);
+
+	irq_hash_out(irq_from_kobject(kobj));
 
 	kobject_put(kobj);
Index: kernel/generic/src/ipc/kbox.c
===================================================================
--- kernel/generic/src/ipc/kbox.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/ipc/kbox.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -242,9 +242,9 @@
 	}
 
-	kobject_t *phone_obj = kobject_get(TASK, phone_handle,
-	    KOBJECT_TYPE_PHONE);
+	phone_t *phone = phone_from_kobject(
+	    kobject_get(TASK, phone_handle, KOBJECT_TYPE_PHONE));
 	/* Connect the newly allocated phone to the kbox */
 	/* Hand over phone_obj's reference to ipc_phone_connect() */
-	(void) ipc_phone_connect(phone_obj->phone, &task->kb.box);
+	(void) ipc_phone_connect(phone, &task->kb.box);
 
 	mutex_unlock(&task->kb.cleanup_lock);
Index: kernel/generic/src/ipc/ops/conctmeto.c
===================================================================
--- kernel/generic/src/ipc/ops/conctmeto.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/ipc/ops/conctmeto.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -88,5 +88,5 @@
 
 	/* Set the recipient-assigned label */
-	pobj->phone->label = ipc_get_arg5(&answer->data);
+	phone_from_kobject(pobj)->label = ipc_get_arg5(&answer->data);
 
 	/* Restore phone handle in answer's ARG5 */
@@ -96,5 +96,5 @@
 	if (ipc_get_retval(&answer->data) == EOK) {
 		/* Hand over reference from pobj to the answerbox */
-		(void) ipc_phone_connect(pobj->phone, &TASK->answerbox);
+		(void) ipc_phone_connect(phone_from_kobject(pobj), &TASK->answerbox);
 	} else {
 		/* Drop the extra reference */
Index: kernel/generic/src/ipc/ops/concttome.c
===================================================================
--- kernel/generic/src/ipc/ops/concttome.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/ipc/ops/concttome.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -49,5 +49,5 @@
 		 * Set the sender-assigned label to the new phone.
 		 */
-		pobj->phone->label = ipc_get_arg5(&call->data);
+		phone_from_kobject(pobj)->label = ipc_get_arg5(&call->data);
 	}
 	call->priv = (sysarg_t) pobj;
@@ -88,5 +88,5 @@
 		kobject_add_ref(pobj);
 
-		if (ipc_phone_connect(pobj->phone,
+		if (ipc_phone_connect(phone_from_kobject(pobj),
 		    &answer->sender->answerbox)) {
 			/* Pass the reference to the capability */
Index: kernel/generic/src/ipc/ops/stchngath.c
===================================================================
--- kernel/generic/src/ipc/ops/stchngath.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/ipc/ops/stchngath.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -45,24 +45,24 @@
 	task_t *other_task_s;
 
-	kobject_t *sender_obj = kobject_get(TASK,
-	    (cap_handle_t) ipc_get_arg5(&call->data), KOBJECT_TYPE_PHONE);
-	if (!sender_obj)
+	phone_t *sender_phone = phone_from_kobject(kobject_get(TASK,
+	    (cap_handle_t) ipc_get_arg5(&call->data), KOBJECT_TYPE_PHONE));
+	if (!sender_phone)
 		return ENOENT;
 
-	mutex_lock(&sender_obj->phone->lock);
-	if (sender_obj->phone->state != IPC_PHONE_CONNECTED) {
-		mutex_unlock(&sender_obj->phone->lock);
-		kobject_put(sender_obj);
+	mutex_lock(&sender_phone->lock);
+	if (sender_phone->state != IPC_PHONE_CONNECTED) {
+		mutex_unlock(&sender_phone->lock);
+		kobject_put(&sender_phone->kobject);
 		return EINVAL;
 	}
 
-	other_task_s = sender_obj->phone->callee->task;
+	other_task_s = sender_phone->callee->task;
 
-	mutex_unlock(&sender_obj->phone->lock);
+	mutex_unlock(&sender_phone->lock);
 
 	/* Remember the third party task hash. */
 	ipc_set_arg5(&call->data, (sysarg_t) other_task_s);
 
-	kobject_put(sender_obj);
+	kobject_put(&sender_phone->kobject);
 	return EOK;
 }
@@ -77,21 +77,21 @@
 		task_t *other_task_r;
 
-		kobject_t *recipient_obj = kobject_get(TASK,
+		phone_t *recipient_phone = phone_from_kobject(kobject_get(TASK,
 		    (cap_handle_t) ipc_get_arg1(&answer->data),
-		    KOBJECT_TYPE_PHONE);
-		if (!recipient_obj) {
+		    KOBJECT_TYPE_PHONE));
+		if (!recipient_phone) {
 			ipc_set_retval(&answer->data, ENOENT);
 			return ENOENT;
 		}
 
-		mutex_lock(&recipient_obj->phone->lock);
-		if (recipient_obj->phone->state != IPC_PHONE_CONNECTED) {
-			mutex_unlock(&recipient_obj->phone->lock);
+		mutex_lock(&recipient_phone->lock);
+		if (recipient_phone->state != IPC_PHONE_CONNECTED) {
+			mutex_unlock(&recipient_phone->lock);
 			ipc_set_retval(&answer->data, EINVAL);
-			kobject_put(recipient_obj);
+			kobject_put(&recipient_phone->kobject);
 			return EINVAL;
 		}
 
-		other_task_r = recipient_obj->phone->callee->task;
+		other_task_r = recipient_phone->callee->task;
 		other_task_s = (task_t *) ipc_get_arg5(olddata);
 
@@ -114,6 +114,6 @@
 		}
 
-		mutex_unlock(&recipient_obj->phone->lock);
-		kobject_put(recipient_obj);
+		mutex_unlock(&recipient_phone->lock);
+		kobject_put(&recipient_phone->kobject);
 	}
 
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/ipc/sysipc.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -199,5 +199,5 @@
 			list_remove(&phone->link);
 			/* Drop callee->connected_phones reference */
-			kobject_put(phone->kobject);
+			kobject_put(&phone->kobject);
 			phone->state = IPC_PHONE_SLAMMED;
 			phone->label = 0;
@@ -273,11 +273,12 @@
 ipc_req_internal(cap_phone_handle_t handle, ipc_data_t *data, sysarg_t priv)
 {
-	kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
-	if (!kobj->phone)
+	phone_t *phone = phone_from_kobject(
+	    kobject_get(TASK, handle, KOBJECT_TYPE_PHONE));
+	if (!phone)
 		return ENOENT;
 
 	call_t *call = ipc_call_alloc();
 	if (!call) {
-		kobject_put(kobj);
+		kobject_put(&phone->kobject);
 		return ENOMEM;
 	}
@@ -286,5 +287,5 @@
 	memcpy(call->data.args, data->args, sizeof(data->args));
 
-	errno_t rc = request_preprocess(call, kobj->phone);
+	errno_t rc = request_preprocess(call, phone);
 	if (!rc) {
 #ifdef CONFIG_UDEBUG
@@ -292,10 +293,10 @@
 #endif
 
-		kobject_add_ref(call->kobject);
-		rc = ipc_call_sync(kobj->phone, call);
+		kobject_add_ref(&call->kobject);
+		rc = ipc_call_sync(phone, call);
 		spinlock_lock(&call->forget_lock);
 		bool forgotten = call->forget;
 		spinlock_unlock(&call->forget_lock);
-		kobject_put(call->kobject);
+		kobject_put(&call->kobject);
 
 #ifdef CONFIG_UDEBUG
@@ -312,5 +313,5 @@
 				 * deallocation.
 				 */
-				kobject_put(call->kobject);
+				kobject_put(&call->kobject);
 			} else {
 				/*
@@ -320,5 +321,5 @@
 				assert(rc == EINTR);
 			}
-			kobject_put(kobj);
+			kobject_put(&phone->kobject);
 			return rc;
 		}
@@ -329,6 +330,6 @@
 
 	memcpy(data->args, call->data.args, sizeof(data->args));
-	kobject_put(call->kobject);
-	kobject_put(kobj);
+	kobject_put(&call->kobject);
+	kobject_put(&phone->kobject);
 
 	return EOK;
@@ -370,10 +371,12 @@
     sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t label)
 {
-	kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
-	if (!kobj)
+	phone_t *phone = phone_from_kobject(
+	    kobject_get(TASK, handle, KOBJECT_TYPE_PHONE));
+
+	if (!phone)
 		return ENOENT;
 
-	if (check_call_limit(kobj->phone)) {
-		kobject_put(kobj);
+	if (check_call_limit(phone)) {
+		kobject_put(&phone->kobject);
 		return ELIMIT;
 	}
@@ -381,5 +384,5 @@
 	call_t *call = ipc_call_alloc();
 	if (!call) {
-		kobject_put(kobj);
+		kobject_put(&phone->kobject);
 		return ENOMEM;
 	}
@@ -399,12 +402,12 @@
 	call->data.answer_label = label;
 
-	errno_t res = request_preprocess(call, kobj->phone);
+	errno_t res = request_preprocess(call, phone);
 
 	if (!res)
-		ipc_call(kobj->phone, call);
+		ipc_call(phone, call);
 	else
-		ipc_backsend_err(kobj->phone, call, res);
-
-	kobject_put(kobj);
+		ipc_backsend_err(phone, call, res);
+
+	kobject_put(&phone->kobject);
 	return EOK;
 }
@@ -422,10 +425,11 @@
     sysarg_t label)
 {
-	kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
-	if (!kobj)
+	phone_t *phone = phone_from_kobject(
+	    kobject_get(TASK, handle, KOBJECT_TYPE_PHONE));
+	if (!phone)
 		return ENOENT;
 
-	if (check_call_limit(kobj->phone)) {
-		kobject_put(kobj);
+	if (check_call_limit(phone)) {
+		kobject_put(&phone->kobject);
 		return ELIMIT;
 	}
@@ -433,5 +437,5 @@
 	call_t *call = ipc_call_alloc();
 	if (!call) {
-		kobject_put(kobj);
+		kobject_put(&phone->kobject);
 		return ENOMEM;
 	}
@@ -440,6 +444,6 @@
 	    sizeof(call->data.args));
 	if (rc != EOK) {
-		kobject_put(call->kobject);
-		kobject_put(kobj);
+		kobject_put(&call->kobject);
+		kobject_put(&phone->kobject);
 		return (sys_errno_t) rc;
 	}
@@ -448,12 +452,12 @@
 	call->data.answer_label = label;
 
-	errno_t res = request_preprocess(call, kobj->phone);
+	errno_t res = request_preprocess(call, phone);
 
 	if (!res)
-		ipc_call(kobj->phone, call);
+		ipc_call(phone, call);
 	else
-		ipc_backsend_err(kobj->phone, call, res);
-
-	kobject_put(kobj);
+		ipc_backsend_err(phone, call, res);
+
+	kobject_put(&phone->kobject);
 	return EOK;
 }
@@ -489,5 +493,5 @@
 		return ENOENT;
 
-	call_t *call = ckobj->call;
+	call_t *call = call_from_kobject(ckobj);
 
 	ipc_data_t old;
@@ -551,5 +555,5 @@
 	}
 
-	rc = ipc_forward(call, pkobj->phone, &TASK->answerbox, mode);
+	rc = ipc_forward(call, phone_from_kobject(pkobj), &TASK->answerbox, mode);
 	if (rc != EOK) {
 		after_forward = true;
@@ -659,5 +663,5 @@
 		return ENOENT;
 
-	call_t *call = kobj->call;
+	call_t *call = call_from_kobject(kobj);
 	assert(!(call->flags & IPC_CALL_ANSWERED));
 
@@ -706,5 +710,5 @@
 		return ENOENT;
 
-	call_t *call = kobj->call;
+	call_t *call = call_from_kobject(kobj);
 	assert(!(call->flags & IPC_CALL_ANSWERED));
 
@@ -751,5 +755,5 @@
 		return ENOENT;
 
-	errno_t rc = ipc_phone_hangup(kobj->phone);
+	errno_t rc = ipc_phone_hangup(phone_from_kobject(kobj));
 	kobject_put(kobj);
 	cap_free(TASK, handle);
@@ -797,5 +801,5 @@
 
 		STRUCT_TO_USPACE(calldata, &call->data);
-		kobject_put(call->kobject);
+		kobject_put(&call->kobject);
 
 		return EOK;
@@ -806,5 +810,5 @@
 
 		if (call->flags & IPC_CALL_DISCARD_ANSWER) {
-			kobject_put(call->kobject);
+			kobject_put(&call->kobject);
 			goto restart;
 		}
@@ -813,5 +817,5 @@
 
 		STRUCT_TO_USPACE(calldata, &call->data);
-		kobject_put(call->kobject);
+		kobject_put(&call->kobject);
 
 		return EOK;
@@ -836,6 +840,6 @@
 		goto error;
 
-	kobject_add_ref(call->kobject);
-	cap_publish(TASK, handle, call->kobject);
+	kobject_add_ref(&call->kobject);
+	cap_publish(TASK, handle, &call->kobject);
 	return EOK;
 
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/proc/task.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -202,4 +202,9 @@
 		return NULL;
 
+	if (caps_task_init(task) != EOK) {
+		slab_free(task_cache, task);
+		return NULL;
+	}
+
 	refcount_init(&task->refcount);
 
@@ -213,6 +218,4 @@
 	task->ucycles = 0;
 	task->kcycles = 0;
-
-	caps_task_init(task);
 
 	task->ipc_info.call_sent = 0;
@@ -249,7 +252,7 @@
 		}
 
-		kobject_t *phone_obj = kobject_get(task, phone_handle,
-		    KOBJECT_TYPE_PHONE);
-		(void) ipc_phone_connect(phone_obj->phone, ipc_box_0);
+		phone_t *phone = phone_from_kobject(
+		    kobject_get(task, phone_handle, KOBJECT_TYPE_PHONE));
+		(void) ipc_phone_connect(phone, ipc_box_0);
 	}
 
@@ -288,4 +291,6 @@
 	 */
 	as_release(task->as);
+
+	caps_task_clear(task);
 
 	slab_free(task_cache, task);
Index: kernel/generic/src/proc/thread.c
===================================================================
--- kernel/generic/src/proc/thread.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/proc/thread.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -446,5 +446,5 @@
 			 */
 			ipc_cleanup();
-			sys_waitq_task_cleanup();
+			caps_task_clear(TASK);
 			LOG("Cleanup of task %" PRIu64 " completed.", TASK->taskid);
 		}
Index: kernel/generic/src/synch/syswaitq.c
===================================================================
--- kernel/generic/src/synch/syswaitq.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/synch/syswaitq.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -48,35 +48,24 @@
 static slab_cache_t *waitq_cache;
 
-static void waitq_destroy(void *arg)
+typedef struct {
+	kobject_t kobject;
+	waitq_t waitq;
+} waitq_kobject_t;
+
+static void waitq_destroy(kobject_t *arg)
 {
-	waitq_t *wq = (waitq_t *) arg;
+	waitq_kobject_t *wq = (waitq_kobject_t *) arg;
 	slab_free(waitq_cache, wq);
 }
 
 kobject_ops_t waitq_kobject_ops = {
-	.destroy = waitq_destroy
+	.destroy = waitq_destroy,
 };
-
-static bool waitq_cap_cleanup_cb(cap_t *cap, void *arg)
-{
-	kobject_t *kobj = cap_unpublish(cap->task, cap->handle,
-	    KOBJECT_TYPE_WAITQ);
-	kobject_put(kobj);
-	cap_free(cap->task, cap->handle);
-	return true;
-}
 
 /** Initialize the user waitq subsystem */
 void sys_waitq_init(void)
 {
-	waitq_cache = slab_cache_create("waitq_t", sizeof(waitq_t), 0, NULL,
-	    NULL, 0);
-}
-
-/** Clean-up all waitq capabilities held by the exiting task */
-void sys_waitq_task_cleanup(void)
-{
-	caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_WAITQ,
-	    waitq_cap_cleanup_cb, NULL);
+	waitq_cache = slab_cache_create("syswaitq_t", sizeof(waitq_kobject_t),
+	    0, NULL, NULL, 0);
 }
 
@@ -90,21 +79,15 @@
 sys_errno_t sys_waitq_create(uspace_ptr_cap_waitq_handle_t whandle)
 {
-	waitq_t *wq = slab_alloc(waitq_cache, FRAME_ATOMIC);
-	if (!wq)
+	waitq_kobject_t *kobj = slab_alloc(waitq_cache, FRAME_ATOMIC);
+	if (!kobj)
 		return (sys_errno_t) ENOMEM;
-	waitq_initialize(wq);
 
-	kobject_t *kobj = kobject_alloc(0);
-	if (!kobj) {
-		slab_free(waitq_cache, wq);
-		return (sys_errno_t) ENOMEM;
-	}
-	kobject_initialize(kobj, KOBJECT_TYPE_WAITQ, wq);
+	kobject_initialize(&kobj->kobject, KOBJECT_TYPE_WAITQ);
+	waitq_initialize(&kobj->waitq);
 
 	cap_handle_t handle;
 	errno_t rc = cap_alloc(TASK, &handle);
 	if (rc != EOK) {
-		slab_free(waitq_cache, wq);
-		kobject_free(kobj);
+		slab_free(waitq_cache, kobj);
 		return (sys_errno_t) rc;
 	}
@@ -113,10 +96,9 @@
 	if (rc != EOK) {
 		cap_free(TASK, handle);
-		kobject_free(kobj);
-		slab_free(waitq_cache, wq);
+		slab_free(waitq_cache, kobj);
 		return (sys_errno_t) rc;
 	}
 
-	cap_publish(TASK, handle, kobj);
+	cap_publish(TASK, handle, &kobj->kobject);
 
 	return (sys_errno_t) EOK;
@@ -151,5 +133,6 @@
     unsigned int flags)
 {
-	kobject_t *kobj = kobject_get(TASK, whandle, KOBJECT_TYPE_WAITQ);
+	waitq_kobject_t *kobj =
+	    (waitq_kobject_t *) kobject_get(TASK, whandle, KOBJECT_TYPE_WAITQ);
 	if (!kobj)
 		return (sys_errno_t) ENOENT;
@@ -159,5 +142,5 @@
 #endif
 
-	errno_t rc = _waitq_sleep_timeout(kobj->waitq, timeout,
+	errno_t rc = _waitq_sleep_timeout(&kobj->waitq, timeout,
 	    SYNCH_FLAGS_INTERRUPTIBLE | flags);
 
@@ -166,5 +149,5 @@
 #endif
 
-	kobject_put(kobj);
+	kobject_put(&kobj->kobject);
 
 	return (sys_errno_t) rc;
@@ -179,11 +162,12 @@
 sys_errno_t sys_waitq_wakeup(cap_waitq_handle_t whandle)
 {
-	kobject_t *kobj = kobject_get(TASK, whandle, KOBJECT_TYPE_WAITQ);
+	waitq_kobject_t *kobj =
+	    (waitq_kobject_t *) kobject_get(TASK, whandle, KOBJECT_TYPE_WAITQ);
 	if (!kobj)
 		return (sys_errno_t) ENOENT;
 
-	waitq_wake_one(kobj->waitq);
+	waitq_wake_one(&kobj->waitq);
 
-	kobject_put(kobj);
+	kobject_put(&kobj->kobject);
 	return (sys_errno_t) EOK;
 }
Index: kernel/generic/src/sysinfo/stats.c
===================================================================
--- kernel/generic/src/sysinfo/stats.c	(revision 0ae9e18465809a5520c51c76be2866b19c48bd0e)
+++ kernel/generic/src/sysinfo/stats.c	(revision efca8dc8dc3139c430b5e421d54a944d04740d07)
@@ -384,5 +384,5 @@
 static bool produce_stats_ipcc_cb(cap_t *cap, void *arg)
 {
-	phone_t *phone = cap->kobject->phone;
+	phone_t *phone = (phone_t *) cap->kobject;
 	ipccs_state_t *state = (ipccs_state_t *) arg;
 
