diff --git a/sys/event/event.c b/sys/event/event.c
index 9e6ac213fe1e28515df12133cdceae44aa7164e2..19fac6d6918241f0867116e8ff8ef96fcf05e57e 100644
--- a/sys/event/event.c
+++ b/sys/event/event.c
@@ -1,11 +1,25 @@
 /*
  * Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
+ *               2018 Freie Universität Berlin
  *
  * This file is subject to the terms and conditions of the GNU Lesser
  * General Public License v2.1. See the file LICENSE in the top level
  * directory for more details.
  */
 
+/**
+ * @ingroup     sys_event
+ * @{
+ *
+ * @file
+ * @brief       Event loop implementation
+ *
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ *
+ * @}
+ */
+
 #include <assert.h>
 
 #include <string.h>
@@ -14,6 +28,12 @@
 #include "clist.h"
 #include "thread.h"
 
+void event_queue_init_detached(event_queue_t *queue)
+{
+    assert(queue);
+    memset(queue, '\0', sizeof(*queue));
+}
+
 void event_queue_init(event_queue_t *queue)
 {
     assert(queue);
@@ -21,17 +41,31 @@ void event_queue_init(event_queue_t *queue)
     queue->waiter = (thread_t *)sched_active_thread;
 }
 
+void event_queue_claim(event_queue_t *queue)
+{
+    assert(queue && (queue->waiter == NULL));
+    queue->waiter = (thread_t *)sched_active_thread;
+}
+
 void event_post(event_queue_t *queue, event_t *event)
 {
-    assert(queue && queue->waiter && event);
+    assert(queue && event);
 
     unsigned state = irq_disable();
     if (!event->list_node.next) {
         clist_rpush(&queue->event_list, &event->list_node);
     }
+    thread_t *waiter = queue->waiter;
     irq_restore(state);
 
-    thread_flags_set(queue->waiter, THREAD_FLAG_EVENT);
+    /* WARNING: there is a minimal chance, that a waiter claims a formerly
+     *          detached queue between the end of the critical section above and
+     *          the block below. In that case, the new waiter will not be woken
+     *          up. This should be fixed at some point once it is safe to call
+     *          thread_flags_set() inside a critical section on all platforms. */
+    if (waiter) {
+        thread_flags_set(waiter, THREAD_FLAG_EVENT);
+    }
 }
 
 void event_cancel(event_queue_t *queue, event_t *event)
@@ -49,8 +83,8 @@ event_t *event_get(event_queue_t *queue)
 {
     unsigned state = irq_disable();
     event_t *result = (event_t *) clist_lpop(&queue->event_list);
-
     irq_restore(state);
+
     if (result) {
         result->list_node.next = NULL;
     }
@@ -59,13 +93,18 @@ event_t *event_get(event_queue_t *queue)
 
 event_t *event_wait(event_queue_t *queue)
 {
-    thread_flags_wait_any(THREAD_FLAG_EVENT);
-    unsigned state = irq_disable();
-    event_t *result = (event_t *) clist_lpop(&queue->event_list);
-    if (clist_rpeek(&queue->event_list)) {
-        queue->waiter->flags |= THREAD_FLAG_EVENT;
-    }
-    irq_restore(state);
+    assert(queue);
+    event_t *result;
+
+    do {
+        unsigned state = irq_disable();
+        result = (event_t *)clist_lpop(&queue->event_list);
+        irq_restore(state);
+        if (result == NULL) {
+            thread_flags_wait_any(THREAD_FLAG_EVENT);
+        }
+    } while (result == NULL);
+
     result->list_node.next = NULL;
     return result;
 }
diff --git a/sys/include/event.h b/sys/include/event.h
index 0727459c912e9669aa689434573d3e3e5ddb18a4..62ddda31c95ba40c1b1cbd88234bc455bebcddf9 100644
--- a/sys/include/event.h
+++ b/sys/include/event.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
+ *               2018 Freie Universität Berlin
  *
  * This file is subject to the terms and conditions of the GNU Lesser
  * General Public License v2.1. See the file LICENSE in the top level
@@ -16,8 +17,12 @@
  * An event queue is basically a FIFO queue of events, with some functions to
  * efficiently and safely handle adding and getting events to / from such a
  * queue.
+ *
  * An event queue is bound to a thread, but any thread or ISR can put events
- * into a queue.
+ * into a queue. In most cases, the owning thread of a queue is set during the
+ * queue's initialization. But it is also possible to initialize a queue in a
+ * detached state from a different context and to set the owning thread
+ * at a later point of time using the event_queue_claim() function.
  *
  * An event is a structure containing a pointer to an event handler. It can be
  * extended to provide context or arguments to the handler.  It can also be
@@ -84,6 +89,7 @@
  * @brief       Event API
  *
  * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
  */
 
 #ifndef EVENT_H
@@ -111,6 +117,11 @@ extern "C" {
  */
 #define EVENT_QUEUE_INIT    { .waiter = (thread_t *)sched_active_thread }
 
+/**
+ * @brief   static initializer for detached event queues
+ */
+#define EVENT_QUEUE_INIT_DETACHED   { 0 }
+
 /**
  * @brief   event structure forward declaration
  */
@@ -146,6 +157,25 @@ typedef struct {
  */
 void event_queue_init(event_queue_t *queue);
 
+/**
+ * @brief   Initialize an event queue not binding it to a thread
+ *
+ * @param[out]  queue   event queue object to initialize
+ */
+void event_queue_init_detached(event_queue_t *queue);
+
+/**
+ * @brief   Bind an event queue to the calling thread
+ *
+ * This function must only be called once and only if the given queue is not
+ * yet bound to a thread.
+ *
+ * @pre     (queue->waiter == NULL)
+ *
+ * @param[out]  queue   event queue object to bind to a thread
+ */
+void event_queue_claim(event_queue_t *queue);
+
 /**
  * @brief   Queue an event
  *
@@ -192,6 +222,8 @@ event_t *event_get(event_queue_t *queue);
  * In order to handle an event retrieved using this function,
  * call event->handler(event).
  *
+ * @note    There can only be a single waiter on a queue!
+ *
  * @param[in]   queue   event queue to get event from
  *
  * @returns     pointer to next event
diff --git a/tests/events/Makefile b/tests/events/Makefile
index c8ab5501b0ab56067966d480009548b919e1368d..28d4631f9b31ea8e27010571b0a7b643417ae8a0 100644
--- a/tests/events/Makefile
+++ b/tests/events/Makefile
@@ -1,5 +1,7 @@
 include ../Makefile.tests_common
 
+BOARD_INSUFFICIENT_MEMORY := arduino-duemilanove arduino-uno
+
 FORCE_ASSERTS = 1
 USEMODULE += event_callback
 USEMODULE += event_timeout
diff --git a/tests/events/main.c b/tests/events/main.c
index 6c6e94b2a02980a665282eac72048a6454999712..bc2672a1af4a16ed801b4438dca71f3d465cbd6c 100644
--- a/tests/events/main.c
+++ b/tests/events/main.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
+ *               2018 Freie Universität Berlin
  *
  * This file is subject to the terms and conditions of the GNU Lesser
  * General Public License v2.1. See the file LICENSE in the top level
@@ -14,6 +15,7 @@
  * @brief       event test application
  *
  * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
  *
  * @}
  */
@@ -25,22 +27,30 @@
 #include "event/timeout.h"
 #include "event/callback.h"
 
-static unsigned order;
+#define STACKSIZE       THREAD_STACKSIZE_DEFAULT
+#define PRIO            (THREAD_PRIORITY_MAIN - 1)
+
+static char stack[STACKSIZE];
+
+static unsigned order = 0;
 static uint32_t before;
 
 static void callback(event_t *arg);
 static void custom_callback(event_t *event);
 static void timed_callback(void *arg);
 static void forbidden_callback(void *arg);
-
+static void delayed_callback1(event_t *arg);
+static void delayed_callback2(event_t *arg);
 
 static event_t event = { .handler = callback };
 static event_t event2 = { .handler = callback };
+static event_t delayed_event1 = { .handler = delayed_callback1 };
+static event_t delayed_event2 = { .handler = delayed_callback2 };
 
 static void callback(event_t *arg)
 {
     order++;
-    assert(order == 1);
+    assert(order == 3);
     assert(arg == &event);
     printf("triggered 0x%08x\n", (unsigned)arg);
 }
@@ -57,7 +67,7 @@ static event_callback_t noevent_callback = EVENT_CALLBACK_INIT(forbidden_callbac
 static void custom_callback(event_t *event)
 {
     order++;
-    assert(order == 2);
+    assert(order == 4);
     assert(event == (event_t *)&custom_event);
     custom_event_t *custom_event = (custom_event_t *)event;
     printf("triggered custom event with text: \"%s\"\n", custom_event->text);
@@ -66,7 +76,7 @@ static void custom_callback(event_t *event)
 static void timed_callback(void *arg)
 {
     order++;
-    assert(order == 3);
+    assert(order == 5);
     assert(arg == event_callback.arg);
     uint32_t now = xtimer_now_usec();
     assert((now - before >= 100000LU));
@@ -85,11 +95,54 @@ static void forbidden_callback(void *arg)
     }
 }
 
+static void delayed_callback1(event_t *arg)
+{
+    order++;
+    assert(order == 1);
+    assert(arg == &delayed_event1);
+    printf("triggered delayed event %p\n", (void *)arg);
+}
+
+static void delayed_callback2(event_t *arg)
+{
+    order++;
+    assert(order == 2);
+    assert(arg == &delayed_event2);
+    printf("triggered delayed event %p\n", (void *)arg);
+}
+
+static void *claiming_thread(void *arg)
+{
+    event_queue_t *dq = (event_queue_t *)arg;
+
+    printf("claiming event queue %p\n", (void *)dq);
+    event_queue_claim(dq);
+    printf("launching event queue %p\n", (void *)dq);
+    event_loop(dq);
+
+    return NULL;
+}
+
 int main(void)
 {
     puts("[START] event test application.\n");
 
-    event_queue_t queue = { .waiter = (thread_t *)sched_active_thread };
+    /* test creation of delayed claiming of a detached event queue */
+    event_queue_t dq;
+    printf("initializing detached event queue %p\n", (void *)&dq);
+    event_queue_init_detached(&dq);
+
+    printf("posting %p\n", (void *)&delayed_event1);
+    event_post(&dq, &delayed_event1);
+    printf("posting %p\n", (void *)&delayed_event2);
+    event_post(&dq, &delayed_event2);
+
+    printf("running thread that will claim event queue %p\n", (void *)&dq);
+    thread_create(stack, sizeof(stack), PRIO, 0, claiming_thread, &dq, "ct");
+
+    /* test posting different kind of events in order to a statically
+     * initialized queue */
+    event_queue_t queue = EVENT_QUEUE_INIT;
     printf("posting 0x%08x\n", (unsigned)&event);
     event_post(&queue, &event);