diff --git a/src/cell.c b/src/cell.c
index 44383417cd42398027f9c46fe2eccddcac9e078c..a08131e7a73fada9e99cf94d14fdfa65c7ad8c3a 100644
--- a/src/cell.c
+++ b/src/cell.c
@@ -207,9 +207,7 @@ int cell_link_foreign_parts(struct cell *c, struct part *parts) {
 #endif
 
   /* Do we have a hydro task at this level? */
-  struct link *l = c->mpi.recv;
-  while (l != NULL && l->t->subtype != task_subtype_xv) l = l->next;
-  if (l != NULL) {
+  if (cell_get_recv(c, task_subtype_xv) != NULL) {
 
     /* Recursively attach the parts */
     const int counts = cell_link_parts(c, parts);
@@ -257,8 +255,8 @@ int cell_link_foreign_gparts(struct cell *c, struct gpart *gparts) {
     error("Linking foreign particles in a local cell!");
 #endif
 
-  /* Do we have a hydro task at this level? */
-  if (c->mpi.grav.recv != NULL) {
+  /* Do we have a gravity task at this level? */
+  if (cell_get_recv(c, task_subtype_gpart) != NULL) {
 
     /* Recursively attach the gparts */
     const int counts = cell_link_gparts(c, gparts);
@@ -305,9 +303,7 @@ int cell_count_parts_for_tasks(const struct cell *c) {
 #endif
 
   /* Do we have a hydro task at this level? */
-  struct link *l = c->mpi.recv;
-  while (l != NULL && l->t->subtype != task_subtype_xv) l = l->next;
-  if (l != NULL) {
+  if (cell_get_recv(c, task_subtype_xv) != NULL) {
     return c->hydro.count;
   }
 
@@ -345,8 +341,8 @@ int cell_count_gparts_for_tasks(const struct cell *c) {
     error("Counting foreign particles in a local cell!");
 #endif
 
-  /* Do we have a hydro task at this level? */
-  if (c->mpi.grav.recv != NULL) {
+  /* Do we have a gravity task at this level? */
+  if (cell_get_recv(c, task_subtype_gpart) != NULL) {
     return c->grav.count;
   }
 
@@ -3453,10 +3449,12 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) {
       if (ci_nodeID != nodeID) {
 
         /* If the local cell is active, receive data from the foreign cell. */
-        if (cj_active) scheduler_activate(s, ci->mpi.grav.recv);
+        if (cj_active)
+          scheduler_activate_recv(s, ci->mpi.recv, task_subtype_gpart);
 
         /* If the foreign cell is active, we want its ti_end values. */
-        if (ci_active) scheduler_activate(s, ci->mpi.grav.recv_ti);
+        if (ci_active)
+          scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_gpart);
 
         /* Is the foreign cell active and will need stuff from us? */
         if (ci_active) {
@@ -3478,10 +3476,12 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) {
       } else if (cj_nodeID != nodeID) {
 
         /* If the local cell is active, receive data from the foreign cell. */
-        if (ci_active) scheduler_activate(s, cj->mpi.grav.recv);
+        if (ci_active)
+          scheduler_activate_recv(s, cj->mpi.recv, task_subtype_gpart);
 
         /* If the foreign cell is active, we want its ti_end values. */
-        if (cj_active) scheduler_activate(s, cj->mpi.grav.recv_ti);
+        if (cj_active)
+          scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_gpart);
 
         /* Is the foreign cell active and will need stuff from us? */
         if (cj_active) {
@@ -3903,7 +3903,7 @@ int cell_has_tasks(struct cell *c) {
 
 #ifdef WITH_MPI
   if (c->timestep != NULL || c->mpi.recv != NULL ||
-      c->mpi.grav.recv_ti != NULL || c->mpi.stars.recv_ti != NULL)
+      c->mpi.stars.recv_ti != NULL)
     return 1;
 #else
   if (c->timestep != NULL) return 1;
diff --git a/src/cell.h b/src/cell.h
index 10e807617e86870ffafe536e54beb1f90a80d64b..f98db484a75528a185bc52145294b501cc136fad 100644
--- a/src/cell.h
+++ b/src/cell.h
@@ -580,14 +580,6 @@ struct cell {
       struct link *recv;
     };
 
-    struct {
-      /* Task receiving gpart data. */
-      struct task *recv;
-
-      /* Task receiving data (time-step). */
-      struct task *recv_ti;
-    } grav;
-
     struct {
       /* Task receiving spart data. */
       struct task *recv;
@@ -1111,4 +1103,23 @@ __attribute__((always_inline)) INLINE static void cell_free_stars_sorts(
   }
 }
 
+/**
+ * @brief Check if a cell has a send/recv task of the given subtype.
+ */
+#ifdef WITH_MPI
+__attribute__((always_inline)) INLINE static struct task *cell_get_send(
+    const struct cell *c, enum task_subtypes subtype) {
+  struct link *l = c->mpi.send;
+  while (l != NULL && l->t->subtype != subtype) l = l->next;
+  return (l != NULL) ? l->t : NULL;
+}
+
+__attribute__((always_inline)) INLINE static struct task *cell_get_recv(
+    const struct cell *c, enum task_subtypes subtype) {
+  struct link *l = c->mpi.recv;
+  while (l != NULL && l->t->subtype != subtype) l = l->next;
+  return (l != NULL) ? l->t : NULL;
+}
+#endif  // WITH_MPI
+
 #endif /* SWIFT_CELL_H */
diff --git a/src/engine.c b/src/engine.c
index dac6fed8b3e08188846399a11bb78b3396ec73d6..c036c077000b77e6213a99aff16e09d2d107d105 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -2394,9 +2394,7 @@ void engine_collect_end_of_step_recurse_hydro(struct cell *c,
   /* Skip super-cells (Their values are already set) */
   if (c->timestep != NULL) return;
 #ifdef WITH_MPI
-  struct link *l = c->mpi.recv;
-  while (l != NULL && l->t->subtype != task_subtype_tend_part) l = l->next;
-  if (l != NULL) return;
+  if (cell_get_recv(c, task_subtype_tend_part) != NULL) return;
 #else
 #endif /* WITH_MPI */
 
@@ -2453,11 +2451,10 @@ void engine_collect_end_of_step_recurse_hydro(struct cell *c,
 void engine_collect_end_of_step_recurse_grav(struct cell *c,
                                              const struct engine *e) {
 
-/* Skip super-cells (Their values are already set) */
-#ifdef WITH_MPI
-  if (c->timestep != NULL || c->mpi.grav.recv_ti != NULL) return;
-#else
+  /* Skip super-cells (Their values are already set) */
   if (c->timestep != NULL) return;
+#ifdef WITH_MPI
+  if (cell_get_recv(c, task_subtype_tend_gpart) != NULL) return;
 #endif /* WITH_MPI */
 
 #ifdef SWIFT_DEBUG_CHECKS
diff --git a/src/engine_maketasks.c b/src/engine_maketasks.c
index 09920a49572ce5c47ca071c0cfd7ef094d0ad612..c657c6ea0b8e1617a8621059dbdd8ab6da9e8fc9 100644
--- a/src/engine_maketasks.c
+++ b/src/engine_maketasks.c
@@ -335,37 +335,38 @@ void engine_addtasks_recv_hydro(struct engine *e, struct cell *c,
     engine_addlink(e, &c->mpi.recv, t_gradient);
 #endif
     engine_addlink(e, &c->mpi.recv, t_ti);
-  }
 
-  /* Add dependencies. */
-  if (c->hydro.sorts != NULL) {
-    scheduler_addunlock(s, t_xv, c->hydro.sorts);
-    scheduler_addunlock(s, c->hydro.sorts, t_rho);
-  }
+    /* Add dependencies. */
+    if (c->hydro.sorts != NULL) {
+      scheduler_addunlock(s, t_xv, c->hydro.sorts);
+      scheduler_addunlock(s, c->hydro.sorts, t_rho);
+    }
 
-  for (struct link *l = c->hydro.density; l != NULL; l = l->next) {
-    scheduler_addunlock(s, t_xv, l->t);
-    scheduler_addunlock(s, l->t, t_rho);
-  }
+    for (struct link *l = c->hydro.density; l != NULL; l = l->next) {
+      scheduler_addunlock(s, t_xv, l->t);
+      scheduler_addunlock(s, l->t, t_rho);
+    }
 #ifdef EXTRA_HYDRO_LOOP
-  for (struct link *l = c->hydro.gradient; l != NULL; l = l->next) {
-    scheduler_addunlock(s, t_rho, l->t);
-    scheduler_addunlock(s, l->t, t_gradient);
-  }
-  for (struct link *l = c->hydro.force; l != NULL; l = l->next) {
-    scheduler_addunlock(s, t_gradient, l->t);
-    scheduler_addunlock(s, l->t, t_ti);
-  }
+    for (struct link *l = c->hydro.gradient; l != NULL; l = l->next) {
+      scheduler_addunlock(s, t_rho, l->t);
+      scheduler_addunlock(s, l->t, t_gradient);
+    }
+    for (struct link *l = c->hydro.force; l != NULL; l = l->next) {
+      scheduler_addunlock(s, t_gradient, l->t);
+      scheduler_addunlock(s, l->t, t_ti);
+    }
 #else
-  for (struct link *l = c->hydro.force; l != NULL; l = l->next) {
-    scheduler_addunlock(s, t_rho, l->t);
-    scheduler_addunlock(s, l->t, t_ti);
-  }
+    for (struct link *l = c->hydro.force; l != NULL; l = l->next) {
+      scheduler_addunlock(s, t_rho, l->t);
+      scheduler_addunlock(s, l->t, t_ti);
+    }
 #endif
 
-  /* Make sure the density has been computed before the stars compute theirs. */
-  for (struct link *l = c->stars.density; l != NULL; l = l->next) {
-    scheduler_addunlock(s, t_rho, l->t);
+    /* Make sure the density has been computed before the stars compute theirs.
+     */
+    for (struct link *l = c->stars.density; l != NULL; l = l->next) {
+      scheduler_addunlock(s, t_rho, l->t);
+    }
   }
 
   /* Recurse? */
@@ -469,14 +470,16 @@ void engine_addtasks_recv_gravity(struct engine *e, struct cell *c,
                              c->mpi.tag, 0, c, NULL);
   }
 
-  c->mpi.grav.recv = t_grav;
-  c->mpi.grav.recv_ti = t_ti;
+  /* If we have tasks, link them. */
+  if (t_grav != NULL) {
+    engine_addlink(e, &c->mpi.recv, t_grav);
+    engine_addlink(e, &c->mpi.recv, t_ti);
 
-  for (struct link *l = c->grav.grav; l != NULL; l = l->next) {
-    scheduler_addunlock(s, t_grav, l->t);
-    scheduler_addunlock(s, l->t, t_ti);
+    for (struct link *l = c->grav.grav; l != NULL; l = l->next) {
+      scheduler_addunlock(s, t_grav, l->t);
+      scheduler_addunlock(s, l->t, t_ti);
+    }
   }
-
   /* Recurse? */
   if (c->split)
     for (int k = 0; k < 8; k++)
diff --git a/src/engine_marktasks.c b/src/engine_marktasks.c
index 859531f4803a076367a03e858bab7b893b6d4a83..731ab43df2a317a036529b6e48b08224c548aad7 100644
--- a/src/engine_marktasks.c
+++ b/src/engine_marktasks.c
@@ -539,10 +539,12 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
         if (ci_nodeID != nodeID) {
 
           /* If the local cell is active, receive data from the foreign cell. */
-          if (cj_active_gravity) scheduler_activate(s, ci->mpi.grav.recv);
+          if (cj_active_gravity)
+            scheduler_activate_recv(s, ci->mpi.recv, task_subtype_gpart);
 
           /* If the foreign cell is active, we want its ti_end values. */
-          if (ci_active_gravity) scheduler_activate(s, ci->mpi.grav.recv_ti);
+          if (ci_active_gravity)
+            scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_gpart);
 
           /* Is the foreign cell active and will need stuff from us? */
           if (ci_active_gravity) {
@@ -564,10 +566,12 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
         } else if (cj_nodeID != nodeID) {
 
           /* If the local cell is active, receive data from the foreign cell. */
-          if (ci_active_gravity) scheduler_activate(s, cj->mpi.grav.recv);
+          if (ci_active_gravity)
+            scheduler_activate_recv(s, cj->mpi.recv, task_subtype_gpart);
 
           /* If the foreign cell is active, we want its ti_end values. */
-          if (cj_active_gravity) scheduler_activate(s, cj->mpi.grav.recv_ti);
+          if (cj_active_gravity)
+            scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_gpart);
 
           /* Is the foreign cell active and will need stuff from us? */
           if (cj_active_gravity) {
diff --git a/src/space.c b/src/space.c
index f6ca47ef448fec9b700adb01c8b782748509e68f..f1e4040b72d775cf11ce9ec04a477aae574517f7 100644
--- a/src/space.c
+++ b/src/space.c
@@ -269,8 +269,6 @@ void space_rebuild_recycle_mapper(void *map_data, int num_elements,
     c->mpi.tag = -1;
 
     c->mpi.recv = NULL;
-    c->mpi.grav.recv = NULL;
-    c->mpi.grav.recv_ti = NULL;
     c->mpi.stars.recv = NULL;
     c->mpi.stars.recv_ti = NULL;
     c->mpi.limiter.recv = NULL;
diff --git a/src/task.h b/src/task.h
index 7bfd49a79904b73a87f3f5a6f0b0176e596d3707..80fd960c7e5d108aa644afc6bc21ae5401505c23 100644
--- a/src/task.h
+++ b/src/task.h
@@ -27,8 +27,12 @@
 
 /* Includes. */
 #include "align.h"
-#include "cell.h"
 #include "cycle.h"
+#include "timeline.h"
+
+/* Forward declarations to avoid circular inclusion dependencies. */
+struct cell;
+struct engine;
 
 #define task_align 128