diff --git a/src/cell.c b/src/cell.c
index 8d72601a410a8b3a84418fd9341cb7a581db9e52..d11c99e3d0da6096256ac4a1a158effe651fd6f5 100644
--- a/src/cell.c
+++ b/src/cell.c
@@ -1167,19 +1167,10 @@ void cell_set_super_mapper(void *map_data, int num_elements, void *extra_data) {
  */
 int cell_has_tasks(struct cell *c) {
 #ifdef WITH_MPI
-  if (c->timestep != NULL || c->mpi.recv != NULL) return 1;
+  return (c->timestep_collect != NULL || c->mpi.recv != NULL);
 #else
-  if (c->timestep != NULL) return 1;
+  return (c->timestep != NULL);
 #endif
-
-  if (c->split) {
-    int count = 0;
-    for (int k = 0; k < 8; ++k)
-      if (c->progeny[k] != NULL) count += cell_has_tasks(c->progeny[k]);
-    return count;
-  } else {
-    return 0;
-  }
 }
 
 /**
diff --git a/src/cell.h b/src/cell.h
index 9e2eda7bb79ca8a26904ddbd05cb17174bfdf217..d21be55b10fa8d2439ef81131fa5e4514d5d8a61 100644
--- a/src/cell.h
+++ b/src/cell.h
@@ -225,37 +225,40 @@ struct pcell {
 /**
  * @brief Cell information at the end of a time-step.
  */
-struct pcell_step_hydro {
+struct pcell_step {
 
-  /*! Minimal integer end-of-timestep in this cell (hydro) */
-  integertime_t ti_end_min;
+  struct {
 
-  /*! Maximal distance any #part has travelled since last rebuild */
-  float dx_max_part;
-};
+    /*! Minimal integer end-of-timestep in this cell (hydro) */
+    integertime_t ti_end_min;
+
+    /*! Maximal distance any #part has travelled since last rebuild */
+    float dx_max_part;
+  } hydro;
 
-struct pcell_step_grav {
+  struct {
 
-  /*! Minimal integer end-of-timestep in this cell (gravity) */
-  integertime_t ti_end_min;
-};
+    /*! Minimal integer end-of-timestep in this cell (gravity) */
+    integertime_t ti_end_min;
+  } grav;
 
-struct pcell_step_stars {
+  struct {
 
-  /*! Minimal integer end-of-timestep in this cell (stars) */
-  integertime_t ti_end_min;
+    /*! Minimal integer end-of-timestep in this cell (stars) */
+    integertime_t ti_end_min;
 
-  /*! Maximal distance any #part has travelled since last rebuild */
-  float dx_max_part;
-};
+    /*! Maximal distance any #part has travelled since last rebuild */
+    float dx_max_part;
+  } stars;
 
-struct pcell_step_black_holes {
+  struct {
 
-  /*! Minimal integer end-of-timestep in this cell (black_holes) */
-  integertime_t ti_end_min;
+    /*! Minimal integer end-of-timestep in this cell (black_holes) */
+    integertime_t ti_end_min;
 
-  /*! Maximal distance any #part has travelled since last rebuild */
-  float dx_max_part;
+    /*! Maximal distance any #part has travelled since last rebuild */
+    float dx_max_part;
+  } black_holes;
 };
 
 /**
@@ -406,6 +409,9 @@ struct cell {
    * feedback */
   struct task *timestep_sync;
 
+  /*! The task to recursively collect time-steps */
+  struct task *timestep_collect;
+
 #ifdef WITH_CSDS
   /*! The csds task */
   struct task *csds;
@@ -484,16 +490,8 @@ void cell_unpack_bpart_swallow(struct cell *c,
                                const struct black_holes_bpart_data *data);
 int cell_pack_tags(const struct cell *c, int *tags);
 int cell_unpack_tags(const int *tags, struct cell *c);
-int cell_pack_end_step_hydro(struct cell *c, struct pcell_step_hydro *pcell);
-int cell_unpack_end_step_hydro(struct cell *c, struct pcell_step_hydro *pcell);
-int cell_pack_end_step_grav(struct cell *c, struct pcell_step_grav *pcell);
-int cell_unpack_end_step_grav(struct cell *c, struct pcell_step_grav *pcell);
-int cell_pack_end_step_stars(struct cell *c, struct pcell_step_stars *pcell);
-int cell_unpack_end_step_stars(struct cell *c, struct pcell_step_stars *pcell);
-int cell_pack_end_step_black_holes(struct cell *c,
-                                   struct pcell_step_black_holes *pcell);
-int cell_unpack_end_step_black_holes(struct cell *c,
-                                     struct pcell_step_black_holes *pcell);
+int cell_pack_end_step(struct cell *c, struct pcell_step *pcell);
+int cell_unpack_end_step(struct cell *c, struct pcell_step *pcell);
 void cell_pack_timebin(const struct cell *const c, timebin_t *const t);
 void cell_unpack_timebin(struct cell *const c, timebin_t *const t);
 int cell_pack_multipoles(struct cell *c, struct gravity_tensors *m);
diff --git a/src/cell_pack.c b/src/cell_pack.c
index 6d20dfc2be79edddc22858e183c4fc1ca14cc1c1..6305ddb6aa7c6a81f40a2422e527d596340c3ba6 100644
--- a/src/cell_pack.c
+++ b/src/cell_pack.c
@@ -273,6 +273,7 @@ int cell_unpack(struct pcell *restrict pc, struct cell *restrict c,
       temp->black_holes.dx_max_part = 0.f;
       temp->nodeID = c->nodeID;
       temp->parent = c;
+      temp->top = c->top;
       c->progeny[k] = temp;
       c->split = 1;
       count += cell_unpack(&pc[pc->progeny[k]], temp, s, with_gravity);
@@ -324,121 +325,27 @@ int cell_unpack_tags(const int *tags, struct cell *restrict c) {
 #endif
 }
 
-/**
- * @brief Pack the time information of the given cell and all it's sub-cells.
- *
- * @param c The #cell.
- * @param pcells (output) The end-of-timestep information we pack into
- *
- * @return The number of packed cells.
- */
-int cell_pack_end_step_hydro(struct cell *restrict c,
-                             struct pcell_step_hydro *restrict pcells) {
-#ifdef WITH_MPI
-
-  /* Pack this cell's data. */
-  pcells[0].ti_end_min = c->hydro.ti_end_min;
-  pcells[0].dx_max_part = c->hydro.dx_max_part;
-
-  /* Fill in the progeny, depth-first recursion. */
-  int count = 1;
-  for (int k = 0; k < 8; k++)
-    if (c->progeny[k] != NULL) {
-      count += cell_pack_end_step_hydro(c->progeny[k], &pcells[count]);
-    }
-
-  /* Return the number of packed values. */
-  return count;
-
-#else
-  error("SWIFT was not compiled with MPI support.");
-  return 0;
-#endif
-}
+int cell_pack_end_step(struct cell *c, struct pcell_step *pcells) {
 
-/**
- * @brief Unpack the time information of a given cell and its sub-cells.
- *
- * @param c The #cell
- * @param pcells The end-of-timestep information to unpack
- *
- * @return The number of cells created.
- */
-int cell_unpack_end_step_hydro(struct cell *restrict c,
-                               struct pcell_step_hydro *restrict pcells) {
-#ifdef WITH_MPI
-
-  /* Unpack this cell's data. */
-  c->hydro.ti_end_min = pcells[0].ti_end_min;
-  c->hydro.dx_max_part = pcells[0].dx_max_part;
-
-  /* Fill in the progeny, depth-first recursion. */
-  int count = 1;
-  for (int k = 0; k < 8; k++)
-    if (c->progeny[k] != NULL) {
-      count += cell_unpack_end_step_hydro(c->progeny[k], &pcells[count]);
-    }
-
-  /* Return the number of packed values. */
-  return count;
-
-#else
-  error("SWIFT was not compiled with MPI support.");
-  return 0;
-#endif
-}
-
-/**
- * @brief Pack the time information of the given cell and all it's sub-cells.
- *
- * @param c The #cell.
- * @param pcells (output) The end-of-timestep information we pack into
- *
- * @return The number of packed cells.
- */
-int cell_pack_end_step_grav(struct cell *restrict c,
-                            struct pcell_step_grav *restrict pcells) {
 #ifdef WITH_MPI
 
   /* Pack this cell's data. */
-  pcells[0].ti_end_min = c->grav.ti_end_min;
+  pcells[0].hydro.ti_end_min = c->hydro.ti_end_min;
+  pcells[0].hydro.dx_max_part = c->hydro.dx_max_part;
 
-  /* Fill in the progeny, depth-first recursion. */
-  int count = 1;
-  for (int k = 0; k < 8; k++)
-    if (c->progeny[k] != NULL) {
-      count += cell_pack_end_step_grav(c->progeny[k], &pcells[count]);
-    }
+  pcells[0].grav.ti_end_min = c->grav.ti_end_min;
 
-  /* Return the number of packed values. */
-  return count;
-
-#else
-  error("SWIFT was not compiled with MPI support.");
-  return 0;
-#endif
-}
-
-/**
- * @brief Unpack the time information of a given cell and its sub-cells.
- *
- * @param c The #cell
- * @param pcells The end-of-timestep information to unpack
- *
- * @return The number of cells created.
- */
-int cell_unpack_end_step_grav(struct cell *restrict c,
-                              struct pcell_step_grav *restrict pcells) {
-#ifdef WITH_MPI
+  pcells[0].stars.ti_end_min = c->stars.ti_end_min;
+  pcells[0].stars.dx_max_part = c->stars.dx_max_part;
 
-  /* Unpack this cell's data. */
-  c->grav.ti_end_min = pcells[0].ti_end_min;
+  pcells[0].black_holes.ti_end_min = c->black_holes.ti_end_min;
+  pcells[0].black_holes.dx_max_part = c->black_holes.dx_max_part;
 
   /* Fill in the progeny, depth-first recursion. */
   int count = 1;
   for (int k = 0; k < 8; k++)
     if (c->progeny[k] != NULL) {
-      count += cell_unpack_end_step_grav(c->progeny[k], &pcells[count]);
+      count += cell_pack_end_step(c->progeny[k], &pcells[count]);
     }
 
   /* Return the number of packed values. */
@@ -450,125 +357,27 @@ int cell_unpack_end_step_grav(struct cell *restrict c,
 #endif
 }
 
-/**
- * @brief Pack the time information of the given cell and all it's sub-cells.
- *
- * @param c The #cell.
- * @param pcells (output) The end-of-timestep information we pack into
- *
- * @return The number of packed cells.
- */
-int cell_pack_end_step_stars(struct cell *restrict c,
-                             struct pcell_step_stars *restrict pcells) {
-#ifdef WITH_MPI
-
-  /* Pack this cell's data. */
-  pcells[0].ti_end_min = c->stars.ti_end_min;
-  pcells[0].dx_max_part = c->stars.dx_max_part;
-
-  /* Fill in the progeny, depth-first recursion. */
-  int count = 1;
-  for (int k = 0; k < 8; k++)
-    if (c->progeny[k] != NULL) {
-      count += cell_pack_end_step_stars(c->progeny[k], &pcells[count]);
-    }
-
-  /* Return the number of packed values. */
-  return count;
-
-#else
-  error("SWIFT was not compiled with MPI support.");
-  return 0;
-#endif
-}
+int cell_unpack_end_step(struct cell *c, struct pcell_step *pcells) {
 
-/**
- * @brief Unpack the time information of a given cell and its sub-cells.
- *
- * @param c The #cell
- * @param pcells The end-of-timestep information to unpack
- *
- * @return The number of cells created.
- */
-int cell_unpack_end_step_stars(struct cell *restrict c,
-                               struct pcell_step_stars *restrict pcells) {
 #ifdef WITH_MPI
 
   /* Unpack this cell's data. */
-  c->stars.ti_end_min = pcells[0].ti_end_min;
-  c->stars.dx_max_part = pcells[0].dx_max_part;
-
-  /* Fill in the progeny, depth-first recursion. */
-  int count = 1;
-  for (int k = 0; k < 8; k++)
-    if (c->progeny[k] != NULL) {
-      count += cell_unpack_end_step_stars(c->progeny[k], &pcells[count]);
-    }
+  c->hydro.ti_end_min = pcells[0].hydro.ti_end_min;
+  c->hydro.dx_max_part = pcells[0].hydro.dx_max_part;
 
-  /* Return the number of packed values. */
-  return count;
+  c->grav.ti_end_min = pcells[0].grav.ti_end_min;
 
-#else
-  error("SWIFT was not compiled with MPI support.");
-  return 0;
-#endif
-}
-
-/**
- * @brief Pack the time information of the given cell and all it's sub-cells.
- *
- * @param c The #cell.
- * @param pcells (output) The end-of-timestep information we pack into
- *
- * @return The number of packed cells.
- */
-int cell_pack_end_step_black_holes(
-    struct cell *restrict c, struct pcell_step_black_holes *restrict pcells) {
-
-#ifdef WITH_MPI
-
-  /* Pack this cell's data. */
-  pcells[0].ti_end_min = c->black_holes.ti_end_min;
-  pcells[0].dx_max_part = c->black_holes.dx_max_part;
-
-  /* Fill in the progeny, depth-first recursion. */
-  int count = 1;
-  for (int k = 0; k < 8; k++)
-    if (c->progeny[k] != NULL) {
-      count += cell_pack_end_step_black_holes(c->progeny[k], &pcells[count]);
-    }
-
-  /* Return the number of packed values. */
-  return count;
-
-#else
-  error("SWIFT was not compiled with MPI support.");
-  return 0;
-#endif
-}
-
-/**
- * @brief Unpack the time information of a given cell and its sub-cells.
- *
- * @param c The #cell
- * @param pcells The end-of-timestep information to unpack
- *
- * @return The number of cells created.
- */
-int cell_unpack_end_step_black_holes(
-    struct cell *restrict c, struct pcell_step_black_holes *restrict pcells) {
-
-#ifdef WITH_MPI
+  c->stars.ti_end_min = pcells[0].stars.ti_end_min;
+  c->stars.dx_max_part = pcells[0].stars.dx_max_part;
 
-  /* Unpack this cell's data. */
-  c->black_holes.ti_end_min = pcells[0].ti_end_min;
-  c->black_holes.dx_max_part = pcells[0].dx_max_part;
+  c->black_holes.ti_end_min = pcells[0].black_holes.ti_end_min;
+  c->black_holes.dx_max_part = pcells[0].black_holes.dx_max_part;
 
   /* Fill in the progeny, depth-first recursion. */
   int count = 1;
   for (int k = 0; k < 8; k++)
     if (c->progeny[k] != NULL) {
-      count += cell_unpack_end_step_black_holes(c->progeny[k], &pcells[count]);
+      count += cell_unpack_end_step(c->progeny[k], &pcells[count]);
     }
 
   /* Return the number of packed values. */
diff --git a/src/cell_unskip.c b/src/cell_unskip.c
index 8750639b7a38f73a29a5f15f6af113140a5b6b53..dae52347ed0aae9ab2c71c4fb88a5038bfd35a3d 100644
--- a/src/cell_unskip.c
+++ b/src/cell_unskip.c
@@ -360,6 +360,7 @@ void cell_activate_sync_part(struct cell *c, struct scheduler *s) {
       error("Trying to activate un-existing c->timestep_sync");
 #endif
     scheduler_activate(s, c->timestep_sync);
+    scheduler_activate(s, c->top->timestep_collect);
     scheduler_activate(s, c->kick1);
   } else {
     for (struct cell *parent = c->parent;
@@ -374,6 +375,7 @@ void cell_activate_sync_part(struct cell *c, struct scheduler *s) {
           error("Trying to activate un-existing parent->timestep_sync");
 #endif
         scheduler_activate(s, parent->timestep_sync);
+        scheduler_activate(s, parent->top->timestep_collect);
         scheduler_activate(s, parent->kick1);
         break;
       }
@@ -554,6 +556,7 @@ void cell_activate_limiter(struct cell *c, struct scheduler *s) {
       error("Trying to activate un-existing c->timestep_limiter");
 #endif
     scheduler_activate(s, c->timestep_limiter);
+    scheduler_activate(s, c->top->timestep_collect);
     scheduler_activate(s, c->kick1);
   } else {
     for (struct cell *parent = c->parent;
@@ -569,6 +572,7 @@ void cell_activate_limiter(struct cell *c, struct scheduler *s) {
           error("Trying to activate un-existing parent->timestep_limiter");
 #endif
         scheduler_activate(s, parent->timestep_limiter);
+        scheduler_activate(s, parent->top->timestep_collect);
         scheduler_activate(s, parent->kick1);
         break;
       }
@@ -1653,10 +1657,6 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) {
           scheduler_activate_unpack(s, ci->mpi.unpack, task_subtype_limiter);
         }
 
-        /* If the foreign cell is active, we want its ti_end values. */
-        if (ci_active)
-          scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_part);
-
         /* Is the foreign cell active and will need stuff from us? */
         if (ci_active) {
 
@@ -1687,22 +1687,14 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) {
                                   ci_nodeID);
         }
 
-        /* If the local cell is active, send its ti_end values. */
-        if (cj_active)
-          scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_part,
-                                  ci_nodeID);
-
         /* Propagating new star counts? */
         if (with_star_formation && with_feedback) {
           if (ci_active && ci->hydro.count > 0) {
             scheduler_activate_recv(s, ci->mpi.recv, task_subtype_sf_counts);
-            scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_spart);
           }
           if (cj_active && cj->hydro.count > 0) {
             scheduler_activate_send(s, cj->mpi.send, task_subtype_sf_counts,
                                     ci_nodeID);
-            scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_spart,
-                                    ci_nodeID);
           }
         }
 
@@ -1726,10 +1718,6 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) {
           scheduler_activate_unpack(s, cj->mpi.unpack, task_subtype_limiter);
         }
 
-        /* If the foreign cell is active, we want its ti_end values. */
-        if (cj_active)
-          scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_part);
-
         /* Is the foreign cell active and will need stuff from us? */
         if (cj_active) {
 
@@ -1761,22 +1749,14 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) {
                                   cj_nodeID);
         }
 
-        /* If the local cell is active, send its ti_end values. */
-        if (ci_active)
-          scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_part,
-                                  cj_nodeID);
-
         /* Propagating new star counts? */
         if (with_star_formation && with_feedback) {
           if (cj_active && cj->hydro.count > 0) {
             scheduler_activate_recv(s, cj->mpi.recv, task_subtype_sf_counts);
-            scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_spart);
           }
           if (ci_active && ci->hydro.count > 0) {
             scheduler_activate_send(s, ci->mpi.send, task_subtype_sf_counts,
                                     cj_nodeID);
-            scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_spart,
-                                    cj_nodeID);
           }
         }
       }
@@ -1802,6 +1782,8 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) {
     if (c->kick1 != NULL) scheduler_activate(s, c->kick1);
     if (c->kick2 != NULL) scheduler_activate(s, c->kick2);
     if (c->timestep != NULL) scheduler_activate(s, c->timestep);
+    if (c->top->timestep_collect != NULL)
+      scheduler_activate(s, c->top->timestep_collect);
     if (c->hydro.end_force != NULL) scheduler_activate(s, c->hydro.end_force);
     if (c->hydro.cooling_in != NULL) cell_activate_cooling(c, s, e);
 #ifdef WITH_CSDS
@@ -1877,10 +1859,6 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) {
         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_recv(s, ci->mpi.recv, task_subtype_tend_gpart);
-
         /* Is the foreign cell active and will need stuff from us? */
         if (ci_active) {
 
@@ -1893,20 +1871,11 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) {
           cell_activate_drift_gpart(cj, s);
         }
 
-        /* If the local cell is active, send its ti_end values. */
-        if (cj_active)
-          scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_gpart,
-                                  ci_nodeID);
-
       } else if (cj_nodeID != nodeID) {
         /* If the local cell is active, receive data from the foreign cell. */
         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_recv(s, cj->mpi.recv, task_subtype_tend_gpart);
-
         /* Is the foreign cell active and will need stuff from us? */
         if (cj_active) {
 
@@ -1918,11 +1887,6 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) {
              itself. */
           cell_activate_drift_gpart(ci, s);
         }
-
-        /* If the local cell is active, send its ti_end values. */
-        if (ci_active)
-          scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_gpart,
-                                  cj_nodeID);
       }
 #endif
     }
@@ -1960,6 +1924,8 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) {
     if (c->kick1 != NULL) scheduler_activate(s, c->kick1);
     if (c->kick2 != NULL) scheduler_activate(s, c->kick2);
     if (c->timestep != NULL) scheduler_activate(s, c->timestep);
+    if (c->top->timestep_collect != NULL)
+      scheduler_activate(s, c->top->timestep_collect);
     if (c->grav.down != NULL) scheduler_activate(s, c->grav.down);
     if (c->grav.down_in != NULL) scheduler_activate(s, c->grav.down_in);
     if (c->grav.long_range != NULL) scheduler_activate(s, c->grav.long_range);
@@ -2130,10 +2096,6 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s,
                                   ci_nodeID);
 #endif
           cell_activate_drift_spart(cj, s);
-
-          /* If the local cell is active, send its ti_end values. */
-          scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_spart,
-                                  ci_nodeID);
         }
 
         if (ci_active) {
@@ -2141,8 +2103,6 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s,
 #ifdef EXTRA_STAR_LOOPS
           scheduler_activate_recv(s, ci->mpi.recv, task_subtype_spart_prep2);
 #endif
-          /* If the foreign cell is active, we want its ti_end values. */
-          scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_spart);
 
           /* Is the foreign cell active and will need stuff from us? */
           scheduler_activate_send(s, cj->mpi.send, task_subtype_xv, ci_nodeID);
@@ -2172,10 +2132,6 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s,
                                   cj_nodeID);
 #endif
           cell_activate_drift_spart(ci, s);
-
-          /* If the local cell is active, send its ti_end values. */
-          scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_spart,
-                                  cj_nodeID);
         }
 
         if (cj_active) {
@@ -2183,8 +2139,6 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s,
 #ifdef EXTRA_STAR_LOOPS
           scheduler_activate_recv(s, cj->mpi.recv, task_subtype_spart_prep2);
 #endif
-          /* If the foreign cell is active, we want its ti_end values. */
-          scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_spart);
 
           /* Is the foreign cell active and will need stuff from us? */
           scheduler_activate_send(s, ci->mpi.send, task_subtype_xv, cj_nodeID);
@@ -2394,6 +2348,8 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s,
       if (c->kick1 != NULL) scheduler_activate(s, c->kick1);
       if (c->kick2 != NULL) scheduler_activate(s, c->kick2);
       if (c->timestep != NULL) scheduler_activate(s, c->timestep);
+      if (c->top->timestep_collect != NULL)
+        scheduler_activate(s, c->top->timestep_collect);
 #ifdef WITH_CSDS
       if (c->csds != NULL) scheduler_activate(s, c->csds);
 #endif
@@ -2510,18 +2466,11 @@ int cell_unskip_black_holes_tasks(struct cell *c, struct scheduler *s) {
         /* Drift before you send */
         cell_activate_drift_bpart(cj, s);
 
-        /* Send the new BH time-steps */
-        scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_bpart,
-                                ci_nodeID);
-
         /* Receive the foreign BHs to tag particles to swallow and for feedback
          */
         scheduler_activate_recv(s, ci->mpi.recv, task_subtype_bpart_rho);
         scheduler_activate_recv(s, ci->mpi.recv, task_subtype_bpart_feedback);
 
-        /* Receive the foreign BH time-steps */
-        scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_bpart);
-
         /* Send the local part information */
         scheduler_activate_send(s, cj->mpi.send, task_subtype_rho, ci_nodeID);
         scheduler_activate_send(s, cj->mpi.send, task_subtype_part_swallow,
@@ -2548,18 +2497,11 @@ int cell_unskip_black_holes_tasks(struct cell *c, struct scheduler *s) {
         /* Drift before you send */
         cell_activate_drift_bpart(ci, s);
 
-        /* Send the new BH time-steps */
-        scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_bpart,
-                                cj_nodeID);
-
         /* Receive the foreign BHs to tag particles to swallow and for feedback
          */
         scheduler_activate_recv(s, cj->mpi.recv, task_subtype_bpart_rho);
         scheduler_activate_recv(s, cj->mpi.recv, task_subtype_bpart_feedback);
 
-        /* Receive the foreign BH time-steps */
-        scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_bpart);
-
         /* Send the local part information */
         scheduler_activate_send(s, ci->mpi.send, task_subtype_rho, cj_nodeID);
         scheduler_activate_send(s, ci->mpi.send, task_subtype_part_swallow,
@@ -2694,6 +2636,8 @@ int cell_unskip_black_holes_tasks(struct cell *c, struct scheduler *s) {
     if (c->kick1 != NULL) scheduler_activate(s, c->kick1);
     if (c->kick2 != NULL) scheduler_activate(s, c->kick2);
     if (c->timestep != NULL) scheduler_activate(s, c->timestep);
+    if (c->top->timestep_collect != NULL)
+      scheduler_activate(s, c->top->timestep_collect);
 #ifdef WITH_CSDS
     if (c->csds != NULL) scheduler_activate(s, c->csds);
 #endif
@@ -2897,6 +2841,8 @@ int cell_unskip_sinks_tasks(struct cell *c, struct scheduler *s) {
     if (c->kick1 != NULL) scheduler_activate(s, c->kick1);
     if (c->kick2 != NULL) scheduler_activate(s, c->kick2);
     if (c->timestep != NULL) scheduler_activate(s, c->timestep);
+    if (c->top->timestep_collect != NULL)
+      scheduler_activate(s, c->top->timestep_collect);
 #ifdef WITH_CSDS
     if (c->csds != NULL) scheduler_activate(s, c->csds);
 #endif
diff --git a/src/engine.c b/src/engine.c
index 92b45dcbe20b3187d0c77d9015b74f2e4b3cb607..12582901b5ee1103ab1038be99ab11c5eca433d9 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -1576,7 +1576,7 @@ void engine_skip_force_and_kick(struct engine *e) {
         t->type == task_type_drift_sink || t->type == task_type_kick1 ||
         t->type == task_type_kick2 || t->type == task_type_timestep ||
         t->type == task_type_timestep_limiter ||
-        t->type == task_type_timestep_sync ||
+        t->type == task_type_timestep_sync || t->type == task_type_collect ||
         t->type == task_type_end_hydro_force || t->type == task_type_cooling ||
         t->type == task_type_stars_in || t->type == task_type_stars_out ||
         t->type == task_type_star_formation ||
@@ -1614,12 +1614,7 @@ void engine_skip_force_and_kick(struct engine *e) {
         t->subtype == task_subtype_sink_compute_formation ||
         t->subtype == task_subtype_sink_merger ||
         t->subtype == task_subtype_sink_accretion ||
-        t->subtype == task_subtype_tend_part ||
-        t->subtype == task_subtype_tend_gpart ||
-        t->subtype == task_subtype_tend_spart ||
-        t->subtype == task_subtype_tend_sink ||
-        t->subtype == task_subtype_tend_bpart ||
-        t->subtype == task_subtype_rho ||
+        t->subtype == task_subtype_tend || t->subtype == task_subtype_rho ||
         t->subtype == task_subtype_spart_density ||
         t->subtype == task_subtype_part_prep1 ||
         t->subtype == task_subtype_spart_prep2 ||
@@ -1925,16 +1920,6 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs,
   if (e->policy & engine_policy_rt)
     space_convert_rt_quantities_after_zeroth_step(e->s, e->verbose);
 
-  /* Since the time-steps may have changed because of the limiter's
-   * action, we need to communicate the new time-step sizes */
-  if ((e->policy & engine_policy_timestep_sync) ||
-      (e->policy & engine_policy_timestep_limiter)) {
-#ifdef WITH_MPI
-    engine_unskip_timestep_communications(e);
-    engine_launch(e, "timesteps");
-#endif
-  }
-
 #ifdef SWIFT_HYDRO_DENSITY_CHECKS
   /* Run the brute-force hydro calculation for some parts */
   if (e->policy & engine_policy_hydro)
@@ -2411,16 +2396,6 @@ void engine_step(struct engine *e) {
   e->systime_last_step = end_systime - start_systime;
 #endif
 
-  /* Since the time-steps may have changed because of the limiter's
-   * action, we need to communicate the new time-step sizes */
-  if ((e->policy & engine_policy_timestep_sync) ||
-      (e->policy & engine_policy_timestep_limiter)) {
-#ifdef WITH_MPI
-    engine_unskip_timestep_communications(e);
-    engine_launch(e, "timesteps");
-#endif
-  }
-
 #ifdef SWIFT_HYDRO_DENSITY_CHECKS
   /* Run the brute-force hydro calculation for some parts */
   if (e->policy & engine_policy_hydro)
diff --git a/src/engine_collect_end_of_step.c b/src/engine_collect_end_of_step.c
index e0935271cb04c295e79a1058bd4a8de0aafb40c9..6a2fca510c058e33a2c96dbd777b9cefbc5798d5 100644
--- a/src/engine_collect_end_of_step.c
+++ b/src/engine_collect_end_of_step.c
@@ -51,272 +51,6 @@ struct end_of_step_data {
   float csds_file_size_gb;
 };
 
-/**
- * @brief Recursive function gathering end-of-step data.
- *
- * We recurse until we encounter a timestep or time-step MPI recv task
- * as the values will have been set at that level. We then bring these
- * values upwards.
- *
- * @param c The #cell to recurse into.
- * @param e The #engine.
- */
-void engine_collect_end_of_step_recurse_hydro(struct cell *c,
-                                              const struct engine *e) {
-
-  /* Skip super-cells (Their values are already set) */
-  if (c->timestep != NULL) return;
-#ifdef WITH_MPI
-  if (cell_get_recv(c, task_subtype_tend_part) != NULL) return;
-#endif /* WITH_MPI */
-
-#ifdef SWIFT_DEBUG_CHECKS
-    /* if (!c->split) error("Reached a leaf without finding a time-step task!
-     * c->depth=%d c->maxdepth=%d c->count=%d c->node=%d", */
-    /* 		       c->depth, c->maxdepth, c->hydro.count, c->nodeID); */
-#endif
-
-  /* Counters for the different quantities. */
-  size_t updated = 0;
-  integertime_t ti_hydro_end_min = max_nr_timesteps, ti_hydro_beg_max = 0;
-
-  /* Collect the values from the progeny. */
-  for (int k = 0; k < 8; k++) {
-    struct cell *cp = c->progeny[k];
-    if (cp != NULL && cp->hydro.count > 0) {
-
-      /* Recurse */
-      engine_collect_end_of_step_recurse_hydro(cp, e);
-
-      /* And update */
-      ti_hydro_end_min = min(ti_hydro_end_min, cp->hydro.ti_end_min);
-      ti_hydro_beg_max = max(ti_hydro_beg_max, cp->hydro.ti_beg_max);
-
-      updated += cp->hydro.updated;
-
-      /* Collected, so clear for next time. */
-      cp->hydro.updated = 0;
-    }
-  }
-
-  /* Store the collected values in the cell. */
-  c->hydro.ti_end_min = ti_hydro_end_min;
-  c->hydro.ti_beg_max = ti_hydro_beg_max;
-  c->hydro.updated = updated;
-}
-
-/**
- * @brief Recursive function gathering end-of-step data.
- *
- * We recurse until we encounter a timestep or time-step MPI recv task
- * as the values will have been set at that level. We then bring these
- * values upwards.
- *
- * @param c The #cell to recurse into.
- * @param e The #engine.
- */
-void engine_collect_end_of_step_recurse_grav(struct cell *c,
-                                             const struct engine *e) {
-
-  /* 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
-    //  if (!c->split) error("Reached a leaf without finding a time-step
-    //  task!");
-#endif
-
-  /* Counters for the different quantities. */
-  size_t updated = 0;
-  integertime_t ti_grav_end_min = max_nr_timesteps, ti_grav_beg_max = 0;
-
-  /* Collect the values from the progeny. */
-  for (int k = 0; k < 8; k++) {
-    struct cell *cp = c->progeny[k];
-    if (cp != NULL && cp->grav.count > 0) {
-
-      /* Recurse */
-      engine_collect_end_of_step_recurse_grav(cp, e);
-
-      /* And update */
-      ti_grav_end_min = min(ti_grav_end_min, cp->grav.ti_end_min);
-      ti_grav_beg_max = max(ti_grav_beg_max, cp->grav.ti_beg_max);
-
-      updated += cp->grav.updated;
-
-      /* Collected, so clear for next time. */
-      cp->grav.updated = 0;
-    }
-  }
-
-  /* Store the collected values in the cell. */
-  c->grav.ti_end_min = ti_grav_end_min;
-  c->grav.ti_beg_max = ti_grav_beg_max;
-  c->grav.updated = updated;
-}
-
-/**
- * @brief Recursive function gathering end-of-step data.
- *
- * We recurse until we encounter a timestep or time-step MPI recv task
- * as the values will have been set at that level. We then bring these
- * values upwards.
- *
- * @param c The #cell to recurse into.
- * @param e The #engine.
- */
-void engine_collect_end_of_step_recurse_stars(struct cell *c,
-                                              const struct engine *e) {
-
-  /* Skip super-cells (Their values are already set) */
-  if (c->timestep != NULL) return;
-#ifdef WITH_MPI
-  if (cell_get_recv(c, task_subtype_tend_spart) != NULL) return;
-#endif /* WITH_MPI */
-
-#ifdef SWIFT_DEBUG_CHECKS
-    // if (!c->split) error("Reached a leaf without finding a time-step task!");
-#endif
-
-  /* Counters for the different quantities. */
-  size_t updated = 0;
-  integertime_t ti_stars_end_min = max_nr_timesteps, ti_stars_beg_max = 0;
-
-  /* Collect the values from the progeny. */
-  for (int k = 0; k < 8; k++) {
-    struct cell *cp = c->progeny[k];
-    if (cp != NULL && cp->stars.count > 0) {
-
-      /* Recurse */
-      engine_collect_end_of_step_recurse_stars(cp, e);
-
-      /* And update */
-      ti_stars_end_min = min(ti_stars_end_min, cp->stars.ti_end_min);
-      ti_stars_beg_max = max(ti_stars_beg_max, cp->stars.ti_beg_max);
-
-      updated += cp->stars.updated;
-
-      /* Collected, so clear for next time. */
-      cp->stars.updated = 0;
-    }
-  }
-
-  /* Store the collected values in the cell. */
-  c->stars.ti_end_min = ti_stars_end_min;
-  c->stars.ti_beg_max = ti_stars_beg_max;
-  c->stars.updated = updated;
-}
-
-/**
- * @brief Recursive function gathering end-of-step data.
- *
- * We recurse until we encounter a timestep or time-step MPI recv task
- * as the values will have been set at that level. We then bring these
- * values upwards.
- *
- * @param c The #cell to recurse into.
- * @param e The #engine.
- */
-void engine_collect_end_of_step_recurse_black_holes(struct cell *c,
-                                                    const struct engine *e) {
-
-  /* Skip super-cells (Their values are already set) */
-  if (c->timestep != NULL) return;
-#ifdef WITH_MPI
-  if (cell_get_recv(c, task_subtype_tend_bpart) != NULL) return;
-#endif /* WITH_MPI */
-
-#ifdef SWIFT_DEBUG_CHECKS
-    // if (!c->split) error("Reached a leaf without finding a time-step task!");
-#endif
-
-  /* Counters for the different quantities. */
-  size_t updated = 0;
-  integertime_t ti_black_holes_end_min = max_nr_timesteps,
-                ti_black_holes_beg_max = 0;
-
-  /* Collect the values from the progeny. */
-  for (int k = 0; k < 8; k++) {
-    struct cell *cp = c->progeny[k];
-    if (cp != NULL && cp->black_holes.count > 0) {
-
-      /* Recurse */
-      engine_collect_end_of_step_recurse_black_holes(cp, e);
-
-      /* And update */
-      ti_black_holes_end_min =
-          min(ti_black_holes_end_min, cp->black_holes.ti_end_min);
-      ti_black_holes_beg_max =
-          max(ti_black_holes_beg_max, cp->black_holes.ti_beg_max);
-
-      updated += cp->black_holes.updated;
-
-      /* Collected, so clear for next time. */
-      cp->black_holes.updated = 0;
-    }
-  }
-
-  /* Store the collected values in the cell. */
-  c->black_holes.ti_end_min = ti_black_holes_end_min;
-  c->black_holes.ti_beg_max = ti_black_holes_beg_max;
-  c->black_holes.updated = updated;
-}
-
-/**
- * @brief Recursive function gathering end-of-step data.
- *
- * We recurse until we encounter a timestep or time-step MPI recv task
- * as the values will have been set at that level. We then bring these
- * values upwards.
- *
- * @param c The #cell to recurse into.
- * @param e The #engine.
- */
-void engine_collect_end_of_step_recurse_sinks(struct cell *c,
-                                              const struct engine *e) {
-
-  /* Skip super-cells (Their values are already set) */
-  if (c->timestep != NULL) return;
-#ifdef WITH_MPI
-  if (cell_get_recv(c, task_subtype_tend_sink) != NULL) return;
-#endif /* WITH_MPI */
-
-#ifdef SWIFT_DEBUG_CHECKS
-    // if (!c->split) error("Reached a leaf without finding a time-step task!");
-#endif
-
-  /* Counters for the different quantities. */
-  size_t updated = 0;
-  integertime_t ti_sinks_end_min = max_nr_timesteps, ti_sinks_beg_max = 0;
-
-  /* Collect the values from the progeny. */
-  for (int k = 0; k < 8; k++) {
-    struct cell *cp = c->progeny[k];
-    if (cp != NULL && cp->sinks.count > 0) {
-
-      /* Recurse */
-      engine_collect_end_of_step_recurse_sinks(cp, e);
-
-      /* And update */
-      ti_sinks_end_min = min(ti_sinks_end_min, cp->sinks.ti_end_min);
-      ti_sinks_beg_max = max(ti_sinks_beg_max, cp->sinks.ti_beg_max);
-
-      updated += cp->sinks.updated;
-
-      /* Collected, so clear for next time. */
-      cp->sinks.updated = 0;
-    }
-  }
-
-  /* Store the collected values in the cell. */
-  c->sinks.ti_end_min = ti_sinks_end_min;
-  c->sinks.ti_beg_max = ti_sinks_beg_max;
-  c->sinks.updated = updated;
-}
-
 /**
  * @brief Mapping function to collect the data from the end of the step
  *
@@ -333,13 +67,6 @@ void engine_collect_end_of_step_mapper(void *map_data, int num_elements,
 
   struct end_of_step_data *data = (struct end_of_step_data *)extra_data;
   const struct engine *e = data->e;
-  const int with_hydro = (e->policy & engine_policy_hydro);
-  const int with_self_grav = (e->policy & engine_policy_self_gravity);
-  const int with_ext_grav = (e->policy & engine_policy_external_gravity);
-  const int with_grav = (with_self_grav || with_ext_grav);
-  const int with_stars = (e->policy & engine_policy_stars);
-  const int with_sinks = (e->policy & engine_policy_sinks);
-  const int with_black_holes = (e->policy & engine_policy_black_holes);
   struct space *s = e->s;
   int *local_cells = (int *)map_data;
   struct star_formation_history *sfh_top = &data->sfh;
@@ -366,24 +93,7 @@ void engine_collect_end_of_step_mapper(void *map_data, int num_elements,
     if (c->hydro.count > 0 || c->grav.count > 0 || c->stars.count > 0 ||
         c->black_holes.count > 0 || c->sinks.count > 0) {
 
-      /* Make the top-cells recurse */
-      if (with_hydro) {
-        engine_collect_end_of_step_recurse_hydro(c, e);
-      }
-      if (with_grav) {
-        engine_collect_end_of_step_recurse_grav(c, e);
-      }
-      if (with_stars) {
-        engine_collect_end_of_step_recurse_stars(c, e);
-      }
-      if (with_sinks) {
-        engine_collect_end_of_step_recurse_sinks(c, e);
-      }
-      if (with_black_holes) {
-        engine_collect_end_of_step_recurse_black_holes(c, e);
-      }
-
-      /* And aggregate */
+      /* Aggregate data */
       if (c->hydro.ti_end_min > e->ti_current)
         ti_hydro_end_min = min(ti_hydro_end_min, c->hydro.ti_end_min);
       ti_hydro_beg_max = max(ti_hydro_beg_max, c->hydro.ti_beg_max);
@@ -523,8 +233,8 @@ void engine_collect_end_of_step(struct engine *e, int apply) {
 
   /* Collect information from the local top-level cells */
   threadpool_map(&e->threadpool, engine_collect_end_of_step_mapper,
-                 s->local_cells_with_tasks_top, s->nr_local_cells_with_tasks,
-                 sizeof(int), threadpool_auto_chunk_size, &data);
+                 s->local_cells_top, s->nr_local_cells, sizeof(int),
+                 threadpool_auto_chunk_size, &data);
 
   /* Get the number of inhibited particles from the space-wide counters
    * since these have been updated atomically during the time-steps. */
diff --git a/src/engine_maketasks.c b/src/engine_maketasks.c
index a9e3095c957fa62d3197887728e4c048f2f99f5b..8e8fcf7284ad0f1a985e758af9c66f012af554f0 100644
--- a/src/engine_maketasks.c
+++ b/src/engine_maketasks.c
@@ -67,11 +67,9 @@ extern int engine_max_parts_per_cooling;
  * @param ci The sending #cell.
  * @param cj Dummy cell containing the nodeID of the receiving node.
  * @param t_grav The send_grav #task, if it has already been created.
- * @param t_ti The recv_ti_end #task, if it has already been created.
  */
 void engine_addtasks_send_gravity(struct engine *e, struct cell *ci,
-                                  struct cell *cj, struct task *t_grav,
-                                  struct task *t_ti) {
+                                  struct cell *cj, struct task *t_grav) {
 
 #ifdef WITH_MPI
   struct link *l = NULL;
@@ -99,28 +97,22 @@ void engine_addtasks_send_gravity(struct engine *e, struct cell *ci,
       t_grav = scheduler_addtask(s, task_type_send, task_subtype_gpart,
                                  ci->mpi.tag, 0, ci, cj);
 
-      t_ti = scheduler_addtask(s, task_type_send, task_subtype_tend_gpart,
-                               ci->mpi.tag, 0, ci, cj);
-
       /* The sends should unlock the down pass. */
       scheduler_addunlock(s, t_grav, ci->grav.super->grav.down);
 
       /* Drift before you send */
       scheduler_addunlock(s, ci->grav.super->grav.drift, t_grav);
-
-      scheduler_addunlock(s, ci->super->timestep, t_ti);
     }
 
     /* Add them to the local cell. */
     engine_addlink(e, &ci->mpi.send, t_grav);
-    engine_addlink(e, &ci->mpi.send, t_ti);
   }
 
   /* Recurse? */
   if (ci->split)
     for (int k = 0; k < 8; k++)
       if (ci->progeny[k] != NULL)
-        engine_addtasks_send_gravity(e, ci->progeny[k], cj, t_grav, t_ti);
+        engine_addtasks_send_gravity(e, ci->progeny[k], cj, t_grav);
 
 #else
   error("SWIFT was not compiled with MPI support.");
@@ -136,18 +128,19 @@ void engine_addtasks_send_gravity(struct engine *e, struct cell *ci,
  * @param t_xv The send_xv #task, if it has already been created.
  * @param t_rho The send_rho #task, if it has already been created.
  * @param t_gradient The send_gradient #task, if already created.
- * @param t_ti The send_ti_end #task, if it has already been created.
  * @param t_prep1 The send_prep1 #task, if it has already been created.
  * @param t_limiter The send_limiter #task, if it has already been created.
  * @param with_feedback Are we running with stellar feedback?
  * @param with_limiter Are we running with the time-step limiter?
  * @param with_sync Are we running with time-step synchronization?
  */
-void engine_addtasks_send_hydro(
-    struct engine *e, struct cell *ci, struct cell *cj, struct task *t_xv,
-    struct task *t_rho, struct task *t_gradient, struct task *t_ti,
-    struct task *t_prep1, struct task *t_limiter, struct task *t_pack_limiter,
-    const int with_feedback, const int with_limiter, const int with_sync) {
+void engine_addtasks_send_hydro(struct engine *e, struct cell *ci,
+                                struct cell *cj, struct task *t_xv,
+                                struct task *t_rho, struct task *t_gradient,
+                                struct task *t_prep1, struct task *t_limiter,
+                                struct task *t_pack_limiter,
+                                const int with_feedback, const int with_limiter,
+                                const int with_sync) {
 
 #ifdef WITH_MPI
   struct link *l = NULL;
@@ -182,9 +175,6 @@ void engine_addtasks_send_hydro(
                                      ci->mpi.tag, 0, ci, cj);
 #endif
 
-      t_ti = scheduler_addtask(s, task_type_send, task_subtype_tend_part,
-                               ci->mpi.tag, 0, ci, cj);
-
       if (with_limiter) {
         t_limiter = scheduler_addtask(s, task_type_send, task_subtype_limiter,
                                       ci->mpi.tag, 0, ci, cj);
@@ -234,7 +224,6 @@ void engine_addtasks_send_hydro(
       /* Drift before you send */
       scheduler_addunlock(s, ci->hydro.super->hydro.drift, t_xv);
 
-      scheduler_addunlock(s, ci->super->timestep, t_ti);
       if (with_limiter)
         scheduler_addunlock(s, ci->super->timestep, t_pack_limiter);
 
@@ -254,7 +243,6 @@ void engine_addtasks_send_hydro(
 #ifdef EXTRA_HYDRO_LOOP
     engine_addlink(e, &ci->mpi.send, t_gradient);
 #endif
-    engine_addlink(e, &ci->mpi.send, t_ti);
     if (with_limiter) {
       engine_addlink(e, &ci->mpi.send, t_limiter);
       engine_addlink(e, &ci->mpi.pack, t_pack_limiter);
@@ -269,8 +257,8 @@ void engine_addtasks_send_hydro(
     for (int k = 0; k < 8; k++)
       if (ci->progeny[k] != NULL)
         engine_addtasks_send_hydro(
-            e, ci->progeny[k], cj, t_xv, t_rho, t_gradient, t_ti, t_prep1,
-            t_limiter, t_pack_limiter, with_feedback, with_limiter, with_sync);
+            e, ci->progeny[k], cj, t_xv, t_rho, t_gradient, t_prep1, t_limiter,
+            t_pack_limiter, with_feedback, with_limiter, with_sync);
 
 #else
   error("SWIFT was not compiled with MPI support.");
@@ -286,13 +274,11 @@ void engine_addtasks_send_hydro(
  * @param t_density The send_density #task, if it has already been created.
  * @param t_prep2 The send_prep2 #task, if it has already been created.
  * @param t_sf_counts The send_sf_counts, if it has been created.
- * @param t_ti The recv_ti_end #task, if it has already been created.
  * @param with_star_formation Are we running with star formation on?
  */
 void engine_addtasks_send_stars(struct engine *e, struct cell *ci,
                                 struct cell *cj, struct task *t_density,
                                 struct task *t_prep2, struct task *t_sf_counts,
-                                struct task *t_ti,
                                 const int with_star_formation) {
 #ifdef SWIFT_DEBUG_CHECKS
   if (e->policy & engine_policy_sinks && e->policy & engine_policy_stars) {
@@ -346,9 +332,6 @@ void engine_addtasks_send_stars(struct engine *e, struct cell *ci,
                                   ci->mpi.tag, 0, ci, cj);
 #endif
 
-      t_ti = scheduler_addtask(s, task_type_send, task_subtype_tend_spart,
-                               ci->mpi.tag, 0, ci, cj);
-
 #ifdef EXTRA_STAR_LOOPS
       /* The first send_stars task should unlock prep1 ghost */
       scheduler_addunlock(s, t_density, ci->hydro.super->stars.prep1_ghost);
@@ -371,9 +354,6 @@ void engine_addtasks_send_stars(struct engine *e, struct cell *ci,
       /* Drift before first send */
       scheduler_addunlock(s, ci->hydro.super->stars.drift, t_density);
 
-      /* Send new time-steps after timestep tasks */
-      scheduler_addunlock(s, ci->super->timestep, t_ti);
-
       if (with_star_formation && ci->hydro.count > 0) {
         scheduler_addunlock(s, t_sf_counts, t_density);
 #ifdef EXTRA_STAR_LOOPS
@@ -386,7 +366,6 @@ void engine_addtasks_send_stars(struct engine *e, struct cell *ci,
 #ifdef EXTRA_STAR_LOOPS
     engine_addlink(e, &ci->mpi.send, t_prep2);
 #endif
-    engine_addlink(e, &ci->mpi.send, t_ti);
     if (with_star_formation && ci->hydro.count > 0) {
       engine_addlink(e, &ci->mpi.send, t_sf_counts);
     }
@@ -397,7 +376,7 @@ void engine_addtasks_send_stars(struct engine *e, struct cell *ci,
     for (int k = 0; k < 8; k++)
       if (ci->progeny[k] != NULL)
         engine_addtasks_send_stars(e, ci->progeny[k], cj, t_density, t_prep2,
-                                   t_sf_counts, t_ti, with_star_formation);
+                                   t_sf_counts, with_star_formation);
 
 #else
   error("SWIFT was not compiled with MPI support.");
@@ -415,14 +394,12 @@ void engine_addtasks_send_stars(struct engine *e, struct cell *ci,
  * @param t_gas_swallow The gas swallow comm. task, if it has already been
  * created.
  * @param t_feedback The send_feed #task, if it has already been created.
- * @param t_ti The recv_ti_end #task, if it has already been created.
  */
 void engine_addtasks_send_black_holes(struct engine *e, struct cell *ci,
                                       struct cell *cj, struct task *t_rho,
                                       struct task *t_bh_merger,
                                       struct task *t_gas_swallow,
-                                      struct task *t_feedback,
-                                      struct task *t_ti) {
+                                      struct task *t_feedback) {
 
 #ifdef WITH_MPI
 
@@ -461,9 +438,6 @@ void engine_addtasks_send_black_holes(struct engine *e, struct cell *ci,
           scheduler_addtask(s, task_type_send, task_subtype_bpart_feedback,
                             ci->mpi.tag, 0, ci, cj);
 
-      t_ti = scheduler_addtask(s, task_type_send, task_subtype_tend_bpart,
-                               ci->mpi.tag, 0, ci, cj);
-
       /* The send_black_holes task should unlock the super_cell's BH exit point
        * task. */
       scheduler_addunlock(s, t_feedback,
@@ -487,15 +461,12 @@ void engine_addtasks_send_black_holes(struct engine *e, struct cell *ci,
                           t_gas_swallow);
       scheduler_addunlock(s, t_gas_swallow,
                           ci->hydro.super->black_holes.swallow_ghost_1);
-
-      scheduler_addunlock(s, ci->super->timestep, t_ti);
     }
 
     engine_addlink(e, &ci->mpi.send, t_rho);
     engine_addlink(e, &ci->mpi.send, t_bh_merger);
     engine_addlink(e, &ci->mpi.send, t_gas_swallow);
     engine_addlink(e, &ci->mpi.send, t_feedback);
-    engine_addlink(e, &ci->mpi.send, t_ti);
   }
 
   /* Recurse? */
@@ -503,8 +474,8 @@ void engine_addtasks_send_black_holes(struct engine *e, struct cell *ci,
     for (int k = 0; k < 8; k++)
       if (ci->progeny[k] != NULL)
         engine_addtasks_send_black_holes(e, ci->progeny[k], cj, t_rho,
-                                         t_bh_merger, t_gas_swallow, t_feedback,
-                                         t_ti);
+                                         t_bh_merger, t_gas_swallow,
+                                         t_feedback);
 
 #else
   error("SWIFT was not compiled with MPI support.");
@@ -519,7 +490,6 @@ void engine_addtasks_send_black_holes(struct engine *e, struct cell *ci,
  * @param t_xv The recv_xv #task, if it has already been created.
  * @param t_rho The recv_rho #task, if it has already been created.
  * @param t_gradient The recv_gradient #task, if it has already been created.
- * @param t_ti The recv_ti_end #task, if it has already been created.
  * @param t_prep1 The recv_prep1 #task, if it has already been created.
  * @param t_limiter The recv_limiter #task, if it has already been created.
  * @param with_feedback Are we running with stellar feedback?
@@ -527,14 +497,11 @@ void engine_addtasks_send_black_holes(struct engine *e, struct cell *ci,
  * @param with_limiter Are we running with the time-step limiter?
  * @param with_sync Are we running with time-step synchronization?
  */
-void engine_addtasks_recv_hydro(struct engine *e, struct cell *c,
-                                struct task *t_xv, struct task *t_rho,
-                                struct task *t_gradient, struct task *t_ti,
-                                struct task *t_prep1, struct task *t_limiter,
-                                struct task *t_unpack_limiter,
-                                const int with_feedback,
-                                const int with_black_holes,
-                                const int with_limiter, const int with_sync) {
+void engine_addtasks_recv_hydro(
+    struct engine *e, struct cell *c, struct task *t_xv, struct task *t_rho,
+    struct task *t_gradient, struct task *t_prep1, struct task *t_limiter,
+    struct task *t_unpack_limiter, struct task *tend, const int with_feedback,
+    const int with_black_holes, const int with_limiter, const int with_sync) {
 
 #ifdef WITH_MPI
   struct scheduler *s = &e->sched;
@@ -563,9 +530,6 @@ void engine_addtasks_recv_hydro(struct engine *e, struct cell *c,
                                    c->mpi.tag, 0, c, NULL);
 #endif
 
-    t_ti = scheduler_addtask(s, task_type_recv, task_subtype_tend_part,
-                             c->mpi.tag, 0, c, NULL);
-
     if (with_limiter) {
       t_limiter = scheduler_addtask(s, task_type_recv, task_subtype_limiter,
                                     c->mpi.tag, 0, c, NULL);
@@ -589,7 +553,6 @@ void engine_addtasks_recv_hydro(struct engine *e, struct cell *c,
 #ifdef EXTRA_HYDRO_LOOP
     engine_addlink(e, &c->mpi.recv, t_gradient);
 #endif
-    engine_addlink(e, &c->mpi.recv, t_ti);
     if (with_limiter) {
       engine_addlink(e, &c->mpi.recv, t_limiter);
       engine_addlink(e, &c->mpi.unpack, t_unpack_limiter);
@@ -615,18 +578,17 @@ void engine_addtasks_recv_hydro(struct engine *e, struct cell *c,
     }
     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);
+      scheduler_addunlock(s, l->t, tend);
     }
 #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);
+      scheduler_addunlock(s, l->t, tend);
     }
 #endif
 
     if (with_limiter) {
       for (struct link *l = c->hydro.limiter; l != NULL; l = l->next) {
-        scheduler_addunlock(s, t_ti, l->t);
         scheduler_addunlock(s, t_unpack_limiter, l->t);
       }
     }
@@ -669,7 +631,7 @@ void engine_addtasks_recv_hydro(struct engine *e, struct cell *c,
     for (int k = 0; k < 8; k++)
       if (c->progeny[k] != NULL)
         engine_addtasks_recv_hydro(e, c->progeny[k], t_xv, t_rho, t_gradient,
-                                   t_ti, t_prep1, t_limiter, t_unpack_limiter,
+                                   t_prep1, t_limiter, t_unpack_limiter, tend,
                                    with_feedback, with_black_holes,
                                    with_limiter, with_sync);
 
@@ -686,12 +648,11 @@ void engine_addtasks_recv_hydro(struct engine *e, struct cell *c,
  * @param t_density The recv_density #task, if it has already been created.
  * @param t_prep2 The recv_prep2 #task, if it has already been created.
  * @param t_sf_counts The recv_sf_counts, if it has been created.
- * @param t_ti The recv_ti_end #task, if it has already been created.
  * @param with_star_formation Are we running with star formation on?
  */
 void engine_addtasks_recv_stars(struct engine *e, struct cell *c,
                                 struct task *t_density, struct task *t_prep2,
-                                struct task *t_sf_counts, struct task *t_ti,
+                                struct task *t_sf_counts, struct task *tend,
                                 const int with_star_formation) {
 #ifdef SWIFT_DEBUG_CHECKS
   if (e->policy & engine_policy_sinks && e->policy & engine_policy_stars) {
@@ -733,9 +694,6 @@ void engine_addtasks_recv_stars(struct engine *e, struct cell *c,
     t_prep2 = scheduler_addtask(s, task_type_recv, task_subtype_spart_prep2,
                                 c->mpi.tag, 0, c, NULL);
 #endif
-    t_ti = scheduler_addtask(s, task_type_recv, task_subtype_tend_spart,
-                             c->mpi.tag, 0, c, NULL);
-
     if (with_star_formation && c->hydro.count > 0) {
 
       /* Receive the stars only once the counts have been received */
@@ -752,7 +710,6 @@ void engine_addtasks_recv_stars(struct engine *e, struct cell *c,
 #ifdef EXTRA_STAR_LOOPS
     engine_addlink(e, &c->mpi.recv, t_prep2);
 #endif
-    engine_addlink(e, &c->mpi.recv, t_ti);
     if (with_star_formation && c->hydro.count > 0) {
       engine_addlink(e, &c->mpi.recv, t_sf_counts);
     }
@@ -787,13 +744,13 @@ void engine_addtasks_recv_stars(struct engine *e, struct cell *c,
     /* Start updating local gas only after sparts have been received */
     for (struct link *l = c->stars.feedback; l != NULL; l = l->next) {
       scheduler_addunlock(s, t_prep2, l->t);
-      scheduler_addunlock(s, l->t, t_ti);
+      scheduler_addunlock(s, l->t, tend);
     }
 #else
     /* Start updating local gas only after sparts have been received */
     for (struct link *l = c->stars.feedback; l != NULL; l = l->next) {
       scheduler_addunlock(s, t_density, l->t);
-      scheduler_addunlock(s, l->t, t_ti);
+      scheduler_addunlock(s, l->t, tend);
     }
 #endif
   }
@@ -803,7 +760,7 @@ void engine_addtasks_recv_stars(struct engine *e, struct cell *c,
     for (int k = 0; k < 8; k++)
       if (c->progeny[k] != NULL)
         engine_addtasks_recv_stars(e, c->progeny[k], t_density, t_prep2,
-                                   t_sf_counts, t_ti, with_star_formation);
+                                   t_sf_counts, tend, with_star_formation);
 
 #else
   error("SWIFT was not compiled with MPI support.");
@@ -820,14 +777,13 @@ void engine_addtasks_recv_stars(struct engine *e, struct cell *c,
  * @param t_gas_swallow The gas swallow comm. task, if it has already been
  * created.
  * @param t_feedback The recv_feed #task, if it has already been created.
- * @param t_ti The recv_ti_end #task, if it has already been created.
  */
 void engine_addtasks_recv_black_holes(struct engine *e, struct cell *c,
                                       struct task *t_rho,
                                       struct task *t_bh_merger,
                                       struct task *t_gas_swallow,
                                       struct task *t_feedback,
-                                      struct task *t_ti) {
+                                      struct task *tend) {
 
 #ifdef WITH_MPI
   struct scheduler *s = &e->sched;
@@ -855,9 +811,6 @@ void engine_addtasks_recv_black_holes(struct engine *e, struct cell *c,
 
     t_feedback = scheduler_addtask(
         s, task_type_recv, task_subtype_bpart_feedback, c->mpi.tag, 0, c, NULL);
-
-    t_ti = scheduler_addtask(s, task_type_recv, task_subtype_tend_bpart,
-                             c->mpi.tag, 0, c, NULL);
   }
 
   if (t_rho != NULL) {
@@ -865,7 +818,6 @@ void engine_addtasks_recv_black_holes(struct engine *e, struct cell *c,
     engine_addlink(e, &c->mpi.recv, t_bh_merger);
     engine_addlink(e, &c->mpi.recv, t_gas_swallow);
     engine_addlink(e, &c->mpi.recv, t_feedback);
-    engine_addlink(e, &c->mpi.recv, t_ti);
 
 #ifdef SWIFT_DEBUG_CHECKS
     if (c->nodeID == e->nodeID) error("Local cell!");
@@ -895,7 +847,7 @@ void engine_addtasks_recv_black_holes(struct engine *e, struct cell *c,
     }
     for (struct link *l = c->black_holes.feedback; l != NULL; l = l->next) {
       scheduler_addunlock(s, t_feedback, l->t);
-      scheduler_addunlock(s, l->t, t_ti);
+      scheduler_addunlock(s, l->t, tend);
     }
   }
 
@@ -904,7 +856,7 @@ void engine_addtasks_recv_black_holes(struct engine *e, struct cell *c,
     for (int k = 0; k < 8; k++)
       if (c->progeny[k] != NULL)
         engine_addtasks_recv_black_holes(e, c->progeny[k], t_rho, t_bh_merger,
-                                         t_gas_swallow, t_feedback, t_ti);
+                                         t_gas_swallow, t_feedback, tend);
 
 #else
   error("SWIFT was not compiled with MPI support.");
@@ -917,10 +869,9 @@ void engine_addtasks_recv_black_holes(struct engine *e, struct cell *c,
  * @param e The #engine.
  * @param c The foreign #cell.
  * @param t_grav The recv_gpart #task, if it has already been created.
- * @param t_ti The recv_ti_end #task, if it has already been created.
  */
 void engine_addtasks_recv_gravity(struct engine *e, struct cell *c,
-                                  struct task *t_grav, struct task *t_ti) {
+                                  struct task *t_grav, struct task *tend) {
 
 #ifdef WITH_MPI
   struct scheduler *s = &e->sched;
@@ -939,19 +890,15 @@ void engine_addtasks_recv_gravity(struct engine *e, struct cell *c,
     /* Create the tasks. */
     t_grav = scheduler_addtask(s, task_type_recv, task_subtype_gpart,
                                c->mpi.tag, 0, c, NULL);
-
-    t_ti = scheduler_addtask(s, task_type_recv, task_subtype_tend_gpart,
-                             c->mpi.tag, 0, c, NULL);
   }
 
   /* 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);
+      scheduler_addunlock(s, l->t, tend);
     }
   }
 
@@ -959,7 +906,7 @@ void engine_addtasks_recv_gravity(struct engine *e, struct cell *c,
   if (c->split)
     for (int k = 0; k < 8; k++)
       if (c->progeny[k] != NULL)
-        engine_addtasks_recv_gravity(e, c->progeny[k], t_grav, t_ti);
+        engine_addtasks_recv_gravity(e, c->progeny[k], t_grav, tend);
 
 #else
   error("SWIFT was not compiled with MPI support.");
@@ -995,6 +942,9 @@ void engine_make_hierarchical_tasks_common(struct engine *e, struct cell *c) {
   /* Are we at the top-level? */
   if (c->top == c && c->nodeID == e->nodeID) {
 
+    c->timestep_collect = scheduler_addtask(s, task_type_collect,
+                                            task_subtype_none, 0, 0, c, NULL);
+
     if (with_star_formation && c->hydro.count > 0) {
       c->hydro.star_formation = scheduler_addtask(
           s, task_type_star_formation, task_subtype_none, 0, 0, c, NULL);
@@ -1059,6 +1009,7 @@ void engine_make_hierarchical_tasks_common(struct engine *e, struct cell *c) {
 
       scheduler_addunlock(s, kick2_or_csds, c->timestep);
       scheduler_addunlock(s, c->timestep, c->kick1);
+      scheduler_addunlock(s, c->timestep, c->top->timestep_collect);
 
       /* Subgrid tasks: star formation */
       if (with_star_formation && c->hydro.count > 0) {
@@ -1082,6 +1033,7 @@ void engine_make_hierarchical_tasks_common(struct engine *e, struct cell *c) {
 
         scheduler_addunlock(s, c->timestep, c->timestep_limiter);
         scheduler_addunlock(s, c->timestep_limiter, c->kick1);
+        scheduler_addunlock(s, c->timestep_limiter, c->top->timestep_collect);
       }
 
       /* Time-step synchronization */
@@ -1092,6 +1044,7 @@ void engine_make_hierarchical_tasks_common(struct engine *e, struct cell *c) {
 
         scheduler_addunlock(s, c->timestep, c->timestep_sync);
         scheduler_addunlock(s, c->timestep_sync, c->kick1);
+        scheduler_addunlock(s, c->timestep_sync, c->top->timestep_collect);
       }
 
       if (with_timestep_limiter && with_timestep_sync) {
@@ -3982,21 +3935,29 @@ void engine_addtasks_send_mapper(void *map_data, int num_elements,
     struct cell *cj = cell_type_pairs[k].cj;
     const int type = cell_type_pairs[k].type;
 
+#ifdef WITH_MPI
+    /* Add the timestep exchange task */
+    struct task *tend = scheduler_addtask(
+        &e->sched, task_type_send, task_subtype_tend, ci->mpi.tag, 0, ci, cj);
+    scheduler_addunlock(&e->sched, ci->timestep_collect, tend);
+    engine_addlink(e, &ci->mpi.send, tend);
+#endif
+
     /* Add the send tasks for the cells in the proxy that have a hydro
      * connection. */
     if ((e->policy & engine_policy_hydro) && (type & proxy_cell_type_hydro))
       engine_addtasks_send_hydro(e, ci, cj, /*t_xv=*/NULL,
                                  /*t_rho=*/NULL, /*t_gradient=*/NULL,
-                                 /*t_ti=*/NULL, /*t_prep1=*/NULL,
+                                 /*t_prep1=*/NULL,
                                  /*t_limiter=*/NULL, /*t_pack_limiter=*/NULL,
                                  with_feedback, with_limiter, with_sync);
 
     /* Add the send tasks for the cells in the proxy that have a stars
      * connection. */
     if ((e->policy & engine_policy_feedback) && (type & proxy_cell_type_hydro))
-      engine_addtasks_send_stars(
-          e, ci, cj, /*t_density=*/NULL, /*t_prep2=*/NULL,
-          /*t_sf_counts=*/NULL, /*t_ti=*/NULL, with_star_formation);
+      engine_addtasks_send_stars(e, ci, cj, /*t_density=*/NULL,
+                                 /*t_prep2=*/NULL,
+                                 /*t_sf_counts=*/NULL, with_star_formation);
 
     /* Add the send tasks for the cells in the proxy that have a black holes
      * connection. */
@@ -4005,14 +3966,13 @@ void engine_addtasks_send_mapper(void *map_data, int num_elements,
       engine_addtasks_send_black_holes(e, ci, cj, /*t_rho=*/NULL,
                                        /*t_swallow=*/NULL,
                                        /*t_gas_swallow=*/NULL,
-                                       /*t_feedback=*/NULL,
-                                       /*t_ti=*/NULL);
+                                       /*t_feedback=*/NULL);
 
     /* Add the send tasks for the cells in the proxy that have a gravity
      * connection. */
     if ((e->policy & engine_policy_self_gravity) &&
         (type & proxy_cell_type_gravity))
-      engine_addtasks_send_gravity(e, ci, cj, NULL, NULL);
+      engine_addtasks_send_gravity(e, ci, cj, /*t_grav=*/NULL);
   }
 }
 
@@ -4036,22 +3996,30 @@ void engine_addtasks_recv_mapper(void *map_data, int num_elements,
   for (int k = 0; k < num_elements; k++) {
     struct cell *ci = cell_type_pairs[k].ci;
     const int type = cell_type_pairs[k].type;
+    struct task *tend = NULL;
+
+#ifdef WITH_MPI
+    /* Add the timestep exchange task */
+    tend = scheduler_addtask(&e->sched, task_type_recv, task_subtype_tend,
+                             ci->mpi.tag, 0, ci, NULL);
+    engine_addlink(e, &ci->mpi.recv, tend);
+#endif
 
     /* Add the recv tasks for the cells in the proxy that have a hydro
      * connection. */
     if ((e->policy & engine_policy_hydro) && (type & proxy_cell_type_hydro))
       engine_addtasks_recv_hydro(e, ci, /*t_xv=*/NULL, /*t_rho=*/NULL,
-                                 /*t_gradient=*/NULL, /*t_ti=*/NULL,
+                                 /*t_gradient=*/NULL,
                                  /*t_prep1=*/NULL,
                                  /*t_limiter=*/NULL, /*t_unpack_limiter=*/NULL,
-                                 with_feedback, with_black_holes, with_limiter,
-                                 with_sync);
+                                 tend, with_feedback, with_black_holes,
+                                 with_limiter, with_sync);
 
     /* Add the recv tasks for the cells in the proxy that have a stars
      * connection. */
     if ((e->policy & engine_policy_feedback) && (type & proxy_cell_type_hydro))
       engine_addtasks_recv_stars(e, ci, /*t_density=*/NULL, /*t_prep2=*/NULL,
-                                 /*t_sf_counts=*/NULL, /*t_ti=*/NULL,
+                                 /*t_sf_counts=*/NULL, tend,
                                  with_star_formation);
 
     /* Add the recv tasks for the cells in the proxy that have a black holes
@@ -4061,14 +4029,13 @@ void engine_addtasks_recv_mapper(void *map_data, int num_elements,
       engine_addtasks_recv_black_holes(e, ci, /*t_rho=*/NULL,
                                        /*t_swallow=*/NULL,
                                        /*t_gas_swallow=*/NULL,
-                                       /*t_feedback=*/NULL,
-                                       /*t_ti=*/NULL);
+                                       /*t_feedback=*/NULL, tend);
 
     /* Add the recv tasks for the cells in the proxy that have a gravity
      * connection. */
     if ((e->policy & engine_policy_self_gravity) &&
         (type & proxy_cell_type_gravity))
-      engine_addtasks_recv_gravity(e, ci, /*t_grav=*/NULL, /*t_ti=*/NULL);
+      engine_addtasks_recv_gravity(e, ci, /*t_grav=*/NULL, tend);
   }
 }
 
diff --git a/src/engine_marktasks.c b/src/engine_marktasks.c
index 258f0e16cae2dbbccbfd6656d41babbfac7bf26e..c1cc4567209b640ae5def59aba769ae174652b6f 100644
--- a/src/engine_marktasks.c
+++ b/src/engine_marktasks.c
@@ -938,10 +938,6 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
             scheduler_activate_unpack(s, ci->mpi.unpack, task_subtype_limiter);
           }
 
-          /* If the foreign cell is active, we want its ti_end values. */
-          if (ci_active_hydro)
-            scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_part);
-
           /* Is the foreign cell active and will need stuff from us? */
           if (ci_active_hydro) {
             struct link *l = scheduler_activate_send(
@@ -973,23 +969,15 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
                                     ci_nodeID);
           }
 
-          /* If the local cell is active, send its ti_end values. */
-          if (cj_active_hydro)
-            scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_part,
-                                    ci_nodeID);
-
           /* Propagating new star counts? */
           if (with_star_formation_sink) error("TODO");
           if (with_star_formation && with_feedback) {
             if (ci_active_hydro && ci->hydro.count > 0) {
               scheduler_activate_recv(s, ci->mpi.recv, task_subtype_sf_counts);
-              scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_spart);
             }
             if (cj_active_hydro && cj->hydro.count > 0) {
               scheduler_activate_send(s, cj->mpi.send, task_subtype_sf_counts,
                                       ci_nodeID);
-              scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_spart,
-                                      ci_nodeID);
             }
           }
 
@@ -1014,10 +1002,6 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
             scheduler_activate_unpack(s, cj->mpi.unpack, task_subtype_limiter);
           }
 
-          /* If the foreign cell is active, we want its ti_end values. */
-          if (cj_active_hydro)
-            scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_part);
-
           /* Is the foreign cell active and will need stuff from us? */
           if (cj_active_hydro) {
 
@@ -1051,23 +1035,15 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
                                     cj_nodeID);
           }
 
-          /* If the local cell is active, send its ti_end values. */
-          if (ci_active_hydro)
-            scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_part,
-                                    cj_nodeID);
-
           /* Propagating new star counts? */
           if (with_star_formation_sink) error("TODO");
           if (with_star_formation && with_feedback) {
             if (cj_active_hydro && cj->hydro.count > 0) {
               scheduler_activate_recv(s, cj->mpi.recv, task_subtype_sf_counts);
-              scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_spart);
             }
             if (ci_active_hydro && ci->hydro.count > 0) {
               scheduler_activate_send(s, ci->mpi.send, task_subtype_sf_counts,
                                       cj_nodeID);
-              scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_spart,
-                                      cj_nodeID);
             }
           }
         }
@@ -1100,10 +1076,6 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
                                     ci_nodeID);
 #endif
             cell_activate_drift_spart(cj, s);
-
-            /* If the local cell is active, send its ti_end values. */
-            scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_spart,
-                                    ci_nodeID);
           }
 
           if (ci_active_stars) {
@@ -1113,9 +1085,6 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
             scheduler_activate_recv(s, ci->mpi.recv, task_subtype_spart_prep2);
 #endif
 
-            /* If the foreign cell is active, we want its ti_end values. */
-            scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_spart);
-
             /* Is the foreign cell active and will need stuff from us? */
             scheduler_activate_send(s, cj->mpi.send, task_subtype_xv,
                                     ci_nodeID);
@@ -1149,10 +1118,6 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
                                     cj_nodeID);
 #endif
             cell_activate_drift_spart(ci, s);
-
-            /* If the local cell is active, send its ti_end values. */
-            scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_spart,
-                                    cj_nodeID);
           }
 
           if (cj_active_stars) {
@@ -1162,9 +1127,6 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
             scheduler_activate_recv(s, cj->mpi.recv, task_subtype_spart_prep2);
 #endif
 
-            /* If the foreign cell is active, we want its ti_end values. */
-            scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_spart);
-
             /* Is the foreign cell active and will need stuff from us? */
             scheduler_activate_send(s, ci->mpi.send, task_subtype_xv,
                                     cj_nodeID);
@@ -1225,18 +1187,11 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
           /* Drift before you send */
           cell_activate_drift_bpart(cj, s);
 
-          /* Send the new BH time-steps */
-          scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_bpart,
-                                  ci_nodeID);
-
           /* Receive the foreign BHs to tag particles to swallow and for
            * feedback */
           scheduler_activate_recv(s, ci->mpi.recv, task_subtype_bpart_rho);
           scheduler_activate_recv(s, ci->mpi.recv, task_subtype_bpart_feedback);
 
-          /* Receive the foreign BH time-steps */
-          scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_bpart);
-
           /* Send the local part information */
           scheduler_activate_send(s, cj->mpi.send, task_subtype_rho, ci_nodeID);
           scheduler_activate_send(s, cj->mpi.send, task_subtype_part_swallow,
@@ -1266,18 +1221,11 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
           /* Drift before you send */
           cell_activate_drift_bpart(ci, s);
 
-          /* Send the new BH time-steps */
-          scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_bpart,
-                                  cj_nodeID);
-
           /* Receive the foreign BHs to tag particles to swallow and for
            * feedback */
           scheduler_activate_recv(s, cj->mpi.recv, task_subtype_bpart_rho);
           scheduler_activate_recv(s, cj->mpi.recv, task_subtype_bpart_feedback);
 
-          /* Receive the foreign BH time-steps */
-          scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_bpart);
-
           /* Send the local part information */
           scheduler_activate_send(s, ci->mpi.send, task_subtype_rho, cj_nodeID);
           scheduler_activate_send(s, ci->mpi.send, task_subtype_part_swallow,
@@ -1303,10 +1251,6 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
           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_recv(s, ci->mpi.recv, task_subtype_tend_gpart);
-
           /* Is the foreign cell active and will need stuff from us? */
           if (ci_active_gravity) {
 
@@ -1319,21 +1263,12 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
             cell_activate_drift_gpart(l->t->ci, s);
           }
 
-          /* If the local cell is active, send its ti_end values. */
-          if (cj_active_gravity)
-            scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_gpart,
-                                    ci_nodeID);
-
         } else if (cj_nodeID != nodeID) {
 
           /* If the local cell is active, receive data from the foreign cell. */
           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_recv(s, cj->mpi.recv, task_subtype_tend_gpart);
-
           /* Is the foreign cell active and will need stuff from us? */
           if (cj_active_gravity) {
 
@@ -1345,11 +1280,6 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
                itself. */
             cell_activate_drift_gpart(l->t->ci, s);
           }
-
-          /* If the local cell is active, send its ti_end values. */
-          if (ci_active_gravity)
-            scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_gpart,
-                                    cj_nodeID);
         }
 #endif
       } /* Only interested in RT tasks as of here. */
@@ -1471,8 +1401,8 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
       if (cell_is_active_black_holes(t->ci, e)) scheduler_activate(s, t);
     }
 
-    /* Time-step? */
-    else if (t_type == task_type_timestep) {
+    /* Time-step or time-step collection? */
+    else if (t_type == task_type_timestep || t_type == task_type_collect) {
       t->ci->hydro.updated = 0;
       t->ci->grav.updated = 0;
       t->ci->stars.updated = 0;
@@ -1484,6 +1414,11 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
         scheduler_activate(s, t);
     }
 
+    else if ((t_type == task_type_send && t_subtype == task_subtype_tend) ||
+             (t_type == task_type_recv && t_subtype == task_subtype_tend)) {
+      scheduler_activate(s, t);
+    }
+
     /* Subgrid tasks: cooling */
     else if (t_type == task_type_cooling || t_type == task_type_cooling_in ||
              t_type == task_type_cooling_out) {
diff --git a/src/engine_unskip.c b/src/engine_unskip.c
index 37b4e224b29a14f008ed5b8e66f582701955abff..eb81c2ad42fb03b970054b2b4112fde79e4f907c 100644
--- a/src/engine_unskip.c
+++ b/src/engine_unskip.c
@@ -423,6 +423,12 @@ void engine_unskip(struct engine *e) {
         memswap(&local_cells[k], &local_cells[num_active_cells], sizeof(int));
       num_active_cells += 1;
     }
+
+    /* Activate the top-level timestep exchange */
+#ifdef WITH_MPI
+    scheduler_activate_all_subtype(&e->sched, c->mpi.send, task_subtype_tend);
+    scheduler_activate_all_subtype(&e->sched, c->mpi.recv, task_subtype_tend);
+#endif
   }
 
   /* What kind of tasks do we have? */
@@ -502,60 +508,3 @@ void engine_unskip(struct engine *e) {
     message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
             clocks_getunit());
 }
-
-void engine_unskip_timestep_communications_mapper(void *map_data,
-                                                  int num_elements,
-                                                  void *extra_data) {
-  /* Unpack the data */
-  struct scheduler *s = (struct scheduler *)extra_data;
-  struct task *const tasks = (struct task *)map_data;
-  const int nr_tasks = num_elements;
-
-  /* Unskip the tasks in this part of the array */
-  for (int i = 0; i < nr_tasks; ++i) {
-
-    struct task *const t = &tasks[i];
-
-    if (t->type == task_type_send || t->type == task_type_recv) {
-
-      if (t->subtype == task_subtype_tend_part ||
-          t->subtype == task_subtype_tend_gpart) {
-
-        scheduler_activate(s, t);
-      }
-    }
-  }
-}
-
-/**
- * @brief Blindly unskips all the tend communications for #part and #gpart.
- *
- * This function is only necessary when running with the time-step limiter
- * or the time-step synchronization policy as the time-steps of inactive
- * sections of the tree might have been changed by these tasks.
- *
- * @param e The #engine.
- */
-void engine_unskip_timestep_communications(struct engine *e) {
-
-#ifdef WITH_MPI
-
-  const ticks tic = getticks();
-
-  struct scheduler *s = &e->sched;
-  struct task *tasks = e->sched.tasks;
-  const int nr_tasks = e->sched.nr_tasks;
-
-  /* Activate all the part and gpart ti_end tasks */
-  threadpool_map(&e->threadpool, engine_unskip_timestep_communications_mapper,
-                 tasks, nr_tasks, sizeof(struct task),
-                 threadpool_auto_chunk_size, s);
-
-  if (e->verbose)
-    message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
-            clocks_getunit());
-
-#else
-  error("SWIFT was not compiled with MPI support.");
-#endif
-}
diff --git a/src/runner.h b/src/runner.h
index 14bc25697b4e7ba06ae172975c2e4d2c2aa5b1a9..6f9bbe582438704153b770dad6628a8d3283808f 100644
--- a/src/runner.h
+++ b/src/runner.h
@@ -114,6 +114,7 @@ void runner_do_drift_bpart(struct runner *r, struct cell *c, int timer);
 void runner_do_kick1(struct runner *r, struct cell *c, int timer);
 void runner_do_kick2(struct runner *r, struct cell *c, int timer);
 void runner_do_timestep(struct runner *r, struct cell *c, int timer);
+void runner_do_timestep_collect(struct runner *r, struct cell *c, int timer);
 void runner_do_end_hydro_force(struct runner *r, struct cell *c, int timer);
 void runner_do_end_grav_force(struct runner *r, struct cell *c, int timer);
 void runner_do_init(struct runner *r, struct cell *c, int timer);
diff --git a/src/runner_main.c b/src/runner_main.c
index 765f2ae5b0be11e54fd4557a215983df3ed72f45..52f5629c6bd9df8a6307174ede7666ad987c5cf9 100644
--- a/src/runner_main.c
+++ b/src/runner_main.c
@@ -507,15 +507,12 @@ void *runner_main(void *data) {
         case task_type_timestep_sync:
           runner_do_sync(r, ci, 0, 1);
           break;
+        case task_type_collect:
+          runner_do_timestep_collect(r, ci, 1);
+          break;
 #ifdef WITH_MPI
         case task_type_send:
-          if (t->subtype == task_subtype_tend_part) {
-            free(t->buff);
-          } else if (t->subtype == task_subtype_tend_gpart) {
-            free(t->buff);
-          } else if (t->subtype == task_subtype_tend_spart) {
-            free(t->buff);
-          } else if (t->subtype == task_subtype_tend_bpart) {
+          if (t->subtype == task_subtype_tend) {
             free(t->buff);
           } else if (t->subtype == task_subtype_sf_counts) {
             free(t->buff);
@@ -528,18 +525,8 @@ void *runner_main(void *data) {
           }
           break;
         case task_type_recv:
-          if (t->subtype == task_subtype_tend_part) {
-            cell_unpack_end_step_hydro(ci, (struct pcell_step_hydro *)t->buff);
-            free(t->buff);
-          } else if (t->subtype == task_subtype_tend_gpart) {
-            cell_unpack_end_step_grav(ci, (struct pcell_step_grav *)t->buff);
-            free(t->buff);
-          } else if (t->subtype == task_subtype_tend_spart) {
-            cell_unpack_end_step_stars(ci, (struct pcell_step_stars *)t->buff);
-            free(t->buff);
-          } else if (t->subtype == task_subtype_tend_bpart) {
-            cell_unpack_end_step_black_holes(
-                ci, (struct pcell_step_black_holes *)t->buff);
+          if (t->subtype == task_subtype_tend) {
+            cell_unpack_end_step(ci, (struct pcell_step *)t->buff);
             free(t->buff);
           } else if (t->subtype == task_subtype_sf_counts) {
             cell_unpack_sf_counts(ci, (struct pcell_sf *)t->buff);
diff --git a/src/runner_time_integration.c b/src/runner_time_integration.c
index cfc918eb1deb066b0ff605132b46f9d2a881dbb9..e37a9a4cf28725046ae359f80185bc0c425f8f8c 100644
--- a/src/runner_time_integration.c
+++ b/src/runner_time_integration.c
@@ -1097,6 +1097,82 @@ void runner_do_timestep(struct runner *r, struct cell *c, const int timer) {
   if (timer) TIMER_TOC(timer_timestep);
 }
 
+void runner_do_timestep_collect(struct runner *r, struct cell *c,
+                                const int timer) {
+
+  /* Early stop if we are at the super level.
+   * The time-step task would have set things at this level already */
+  if (c->super == c) return;
+
+  /* Counters for the different quantities. */
+  size_t h_updated = 0;
+  size_t g_updated = 0;
+  size_t s_updated = 0;
+  size_t b_updated = 0;
+  size_t si_updated = 0;
+  integertime_t ti_hydro_end_min = max_nr_timesteps, ti_hydro_beg_max = 0;
+  integertime_t ti_grav_end_min = max_nr_timesteps, ti_grav_beg_max = 0;
+  integertime_t ti_stars_end_min = max_nr_timesteps, ti_stars_beg_max = 0;
+  integertime_t ti_black_holes_end_min = max_nr_timesteps,
+                ti_black_holes_beg_max = 0;
+  integertime_t ti_sinks_end_min = max_nr_timesteps, ti_sinks_beg_max = 0;
+
+  /* Collect the values from the progeny. */
+  for (int k = 0; k < 8; k++) {
+    struct cell *cp = c->progeny[k];
+    if (cp != NULL) {
+
+      /* Recurse */
+      runner_do_timestep_collect(r, c, 0);
+
+      /* And update */
+      ti_hydro_end_min = min(ti_hydro_end_min, cp->hydro.ti_end_min);
+      ti_hydro_beg_max = max(ti_hydro_beg_max, cp->hydro.ti_beg_max);
+      ti_grav_end_min = min(ti_grav_end_min, cp->grav.ti_end_min);
+      ti_grav_beg_max = max(ti_grav_beg_max, cp->grav.ti_beg_max);
+      ti_stars_end_min = min(ti_stars_end_min, cp->stars.ti_end_min);
+      ti_stars_beg_max = max(ti_stars_beg_max, cp->stars.ti_beg_max);
+      ti_black_holes_end_min =
+          min(ti_black_holes_end_min, cp->black_holes.ti_end_min);
+      ti_black_holes_beg_max =
+          max(ti_black_holes_beg_max, cp->black_holes.ti_beg_max);
+      ti_sinks_end_min = min(ti_sinks_end_min, cp->sinks.ti_end_min);
+      ti_sinks_beg_max = max(ti_sinks_beg_max, cp->sinks.ti_beg_max);
+
+      h_updated += cp->hydro.updated;
+      g_updated += cp->grav.updated;
+      s_updated += cp->stars.updated;
+      b_updated += cp->black_holes.updated;
+      si_updated += cp->sinks.updated;
+
+      /* Collected, so clear for next time. */
+      cp->hydro.updated = 0;
+      cp->grav.updated = 0;
+      cp->stars.updated = 0;
+      cp->black_holes.updated = 0;
+      cp->sinks.updated = 0;
+    }
+  }
+
+  /* Store the collected values in the cell. */
+  c->hydro.ti_end_min = ti_hydro_end_min;
+  c->hydro.ti_beg_max = ti_hydro_beg_max;
+  c->grav.ti_end_min = ti_grav_end_min;
+  c->grav.ti_beg_max = ti_grav_beg_max;
+  c->stars.ti_end_min = ti_stars_end_min;
+  c->stars.ti_beg_max = ti_stars_beg_max;
+  c->black_holes.ti_end_min = ti_black_holes_end_min;
+  c->black_holes.ti_beg_max = ti_black_holes_beg_max;
+  c->sinks.ti_end_min = ti_sinks_end_min;
+  c->sinks.ti_beg_max = ti_sinks_beg_max;
+
+  c->hydro.updated = h_updated;
+  c->grav.updated = g_updated;
+  c->stars.updated = s_updated;
+  c->black_holes.updated = b_updated;
+  c->sinks.updated = si_updated;
+}
+
 /**
  * @brief Apply the time-step limiter to all awaken particles in a cell
  * hierarchy.
diff --git a/src/scheduler.c b/src/scheduler.c
index cddc5f12ebec7b81eaa0f70875e93696adfc2dbb..bb93cd40cece2541ece1d7102c47d4f5aa2e4437 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -2042,27 +2042,9 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) {
         MPI_Datatype type = MPI_BYTE; /* Type of the elements */
         void *buff = NULL;            /* Buffer to accept elements */
 
-        if (t->subtype == task_subtype_tend_part) {
+        if (t->subtype == task_subtype_tend) {
 
-          count = size =
-              t->ci->mpi.pcell_size * sizeof(struct pcell_step_hydro);
-          buff = t->buff = malloc(count);
-
-        } else if (t->subtype == task_subtype_tend_gpart) {
-
-          count = size = t->ci->mpi.pcell_size * sizeof(struct pcell_step_grav);
-          buff = t->buff = malloc(count);
-
-        } else if (t->subtype == task_subtype_tend_spart) {
-
-          count = size =
-              t->ci->mpi.pcell_size * sizeof(struct pcell_step_stars);
-          buff = t->buff = malloc(count);
-
-        } else if (t->subtype == task_subtype_tend_bpart) {
-
-          count = size =
-              t->ci->mpi.pcell_size * sizeof(struct pcell_step_black_holes);
+          count = size = t->ci->mpi.pcell_size * sizeof(struct pcell_step);
           buff = t->buff = malloc(count);
 
         } else if (t->subtype == task_subtype_part_swallow) {
@@ -2160,33 +2142,11 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) {
         MPI_Datatype type = MPI_BYTE; /* Type of the elements */
         void *buff = NULL;            /* Buffer to send */
 
-        if (t->subtype == task_subtype_tend_part) {
+        if (t->subtype == task_subtype_tend) {
 
-          size = count =
-              t->ci->mpi.pcell_size * sizeof(struct pcell_step_hydro);
-          buff = t->buff = malloc(size);
-          cell_pack_end_step_hydro(t->ci, (struct pcell_step_hydro *)buff);
-
-        } else if (t->subtype == task_subtype_tend_gpart) {
-
-          size = count = t->ci->mpi.pcell_size * sizeof(struct pcell_step_grav);
-          buff = t->buff = malloc(size);
-          cell_pack_end_step_grav(t->ci, (struct pcell_step_grav *)buff);
-
-        } else if (t->subtype == task_subtype_tend_spart) {
-
-          size = count =
-              t->ci->mpi.pcell_size * sizeof(struct pcell_step_stars);
-          buff = t->buff = malloc(size);
-          cell_pack_end_step_stars(t->ci, (struct pcell_step_stars *)buff);
-
-        } else if (t->subtype == task_subtype_tend_bpart) {
-
-          size = count =
-              t->ci->mpi.pcell_size * sizeof(struct pcell_step_black_holes);
+          size = count = t->ci->mpi.pcell_size * sizeof(struct pcell_step);
           buff = t->buff = malloc(size);
-          cell_pack_end_step_black_holes(t->ci,
-                                         (struct pcell_step_black_holes *)buff);
+          cell_pack_end_step(t->ci, (struct pcell_step *)buff);
 
         } else if (t->subtype == task_subtype_part_swallow) {
 
diff --git a/src/scheduler.h b/src/scheduler.h
index f55f95a0bba292fd5125cbcd39c146bfb5586739..c7c9b1412458f49950087f695705e22bfd1b9582 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -143,6 +143,24 @@ __attribute__((always_inline)) INLINE static void scheduler_activate(
   }
 }
 
+/**
+ * @brief Search a given linked list of task for a given subtype and activate
+ * it.
+ *
+ * @param s The #scheduler.
+ * @param link The first element in the linked list of links for the task of
+ * interest.
+ * @param subtype the task subtype to activate.
+ */
+__attribute__((always_inline)) INLINE static void
+scheduler_activate_all_subtype(struct scheduler *s, struct link *link,
+                               const enum task_subtypes subtype) {
+
+  for (struct link *l = link; l != NULL; l = l->next) {
+    if (l->t->subtype == subtype) scheduler_activate(s, l->t);
+  }
+}
+
 /**
  * @brief Search and add an MPI send task to the list of active tasks.
  *
@@ -156,7 +174,7 @@ __attribute__((always_inline)) INLINE static void scheduler_activate(
  */
 __attribute__((always_inline)) INLINE static struct link *
 scheduler_activate_send(struct scheduler *s, struct link *link,
-                        enum task_subtypes subtype, int nodeID) {
+                        const enum task_subtypes subtype, const int nodeID) {
   struct link *l = NULL;
   for (l = link;
        l != NULL && !(l->t->cj->nodeID == nodeID && l->t->subtype == subtype);
@@ -181,7 +199,7 @@ scheduler_activate_send(struct scheduler *s, struct link *link,
  */
 __attribute__((always_inline)) INLINE static struct link *
 scheduler_activate_recv(struct scheduler *s, struct link *link,
-                        enum task_subtypes subtype) {
+                        const enum task_subtypes subtype) {
   struct link *l = NULL;
   for (l = link; l != NULL && l->t->subtype != subtype; l = l->next)
     ;
diff --git a/src/space_recycle.c b/src/space_recycle.c
index f3781167f290a09d43019e5d261b4507a3133cfc..5a0d74a5fb1c5490bc82793944e4cd8a34457162 100644
--- a/src/space_recycle.c
+++ b/src/space_recycle.c
@@ -158,6 +158,7 @@ void space_rebuild_recycle_mapper(void *map_data, int num_elements,
     c->timestep = NULL;
     c->timestep_limiter = NULL;
     c->timestep_sync = NULL;
+    c->timestep_collect = NULL;
     c->hydro.end_force = NULL;
     c->hydro.drift = NULL;
     c->sinks.drift = NULL;
diff --git a/src/task.c b/src/task.c
index 12080542cf5e9d785a5107c40bb4928245986237..650a7f43a0a21869a7794fb867db4e764364d0bd 100644
--- a/src/task.c
+++ b/src/task.c
@@ -74,6 +74,7 @@ const char *taskID_names[task_type_count] = {
     "timestep",
     "timestep_limiter",
     "timestep_sync",
+    "collect",
     "send",
     "recv",
     "pack",
@@ -131,11 +132,7 @@ const char *subtaskID_names[task_subtype_count] = {
     "limiter",
     "grav",
     "external_grav",
-    "tend_part",
-    "tend_gpart",
-    "tend_spart",
-    "tend_sink",
-    "tend_bpart",
+    "tend",
     "xv",
     "rho",
     "part_swallow",
@@ -1777,6 +1774,7 @@ enum task_categories task_get_category(const struct task *t) {
     case task_type_kick1:
     case task_type_kick2:
     case task_type_timestep:
+    case task_type_collect:
       return task_category_time_integration;
 
     case task_type_timestep_limiter:
diff --git a/src/task.h b/src/task.h
index f579f152ee032e621c21b6f0778ce5013a7bd875..2725696f71dea423db2c303297015f62767515df 100644
--- a/src/task.h
+++ b/src/task.h
@@ -67,6 +67,7 @@ enum task_types {
   task_type_timestep,
   task_type_timestep_limiter,
   task_type_timestep_sync,
+  task_type_collect,
   task_type_send,
   task_type_recv,
   task_type_pack,
@@ -127,11 +128,7 @@ enum task_subtypes {
   task_subtype_limiter,
   task_subtype_grav,
   task_subtype_external_grav,
-  task_subtype_tend_part,
-  task_subtype_tend_gpart,
-  task_subtype_tend_spart,
-  task_subtype_tend_sink,
-  task_subtype_tend_bpart,
+  task_subtype_tend,
   task_subtype_xv,
   task_subtype_rho,
   task_subtype_part_swallow,
diff --git a/tools/task_plots/swift_hardcoded_data.py b/tools/task_plots/swift_hardcoded_data.py
index 6f31bacf4d4a1e24299e20b591a7afd8ee32331c..8beb97e07a95c3f1367a62f2f51df01ac45aac72 100644
--- a/tools/task_plots/swift_hardcoded_data.py
+++ b/tools/task_plots/swift_hardcoded_data.py
@@ -34,6 +34,7 @@ TASKTYPES = [
     "timestep",
     "timestep_limiter",
     "timestep_sync",
+    "collect",
     "send",
     "recv",
     "pack",
@@ -89,11 +90,7 @@ SUBTYPES = [
     "limiter",
     "grav",
     "external_grav",
-    "tend_part",
-    "tend_gpart",
-    "tend_spart",
-    "tend_sink",
-    "tend_bpart",
+    "tend",
     "xv",
     "rho",
     "part_swallow",