diff --git a/examples/dimming/dimming_client/src/main.c b/examples/dimming/dimming_client/src/main.c
index f8aaa086c..f42cd5159 100644
--- a/examples/dimming/dimming_client/src/main.c
+++ b/examples/dimming/dimming_client/src/main.c
@@ -249,7 +249,7 @@ static void button_event_handler(uint32_t button_number)
     static generic_level_move_set_params_t move_set_params = {0};
     static generic_level_delta_set_params_t delta_set_params = {0};
     model_transition_t transition_params;
-    static uint32_t timestamp = 0;
+    static timestamp_t timestamp = 0;
     timestamp_t current_time;
 
     switch(button_number)
diff --git a/examples/enocean_switch/src/main.c b/examples/enocean_switch/src/main.c
index c95c727c3..fc390c897 100644
--- a/examples/enocean_switch/src/main.c
+++ b/examples/enocean_switch/src/main.c
@@ -254,7 +254,7 @@ static void rx_callback(const nrf_mesh_adv_packet_rx_data_t * p_rx_data)
 
 static void app_switch_debounce(enocean_switch_status_t * p_status, uint8_t index)
 {
-    uint32_t timestamp = timer_now();
+    timestamp_t timestamp = timer_now();
     uint32_t status = NRF_ERROR_INTERNAL;
     generic_onoff_set_params_t set_params;
     model_transition_t transition_params;
diff --git a/examples/light_ctl/ctl_client/src/main.c b/examples/light_ctl/ctl_client/src/main.c
index 8dea1b304..f6d8f9caa 100644
--- a/examples/light_ctl/ctl_client/src/main.c
+++ b/examples/light_ctl/ctl_client/src/main.c
@@ -343,7 +343,7 @@ static void button_event_handler(uint32_t button_number)
     uint32_t status = NRF_SUCCESS;
     static uint8_t client = 0;
     model_transition_t transition_params;
-    static uint32_t timestamp = 0;
+    static timestamp_t timestamp = 0;
     timestamp_t current_time;
 
     switch(button_number)
diff --git a/examples/light_lightness/client/src/main.c b/examples/light_lightness/client/src/main.c
index 5b9a997e6..4f8f0ba77 100644
--- a/examples/light_lightness/client/src/main.c
+++ b/examples/light_lightness/client/src/main.c
@@ -330,7 +330,7 @@ static void button_event_handler(uint32_t button_number)
     static light_lightness_default_set_params_t default_set_params = {0};
     static light_lightness_range_set_params_t range_set_params = {1, 65535};
     model_transition_t transition_params;
-    static uint32_t timestamp = 0;
+    static timestamp_t timestamp = 0;
     timestamp_t current_time;
 
     switch(button_number)
diff --git a/mesh/access/api/access_reliable.h b/mesh/access/api/access_reliable.h
index 8eabb0187..765813765 100644
--- a/mesh/access/api/access_reliable.h
+++ b/mesh/access/api/access_reliable.h
@@ -148,7 +148,7 @@ typedef struct
      * Relative acknowledged message timeout.
      * That is, the time from access_model_reliable_publish() is called to the message is timed out.
      */
-    uint32_t timeout;
+    timestamp_t timeout;
     /** Callback to call after the acknowledged transfer has ended. */
     access_reliable_cb_t status_cb;
 } access_reliable_t;
diff --git a/mesh/access/include/access_publish.h b/mesh/access/include/access_publish.h
index 5e69d48ba..79509699c 100644
--- a/mesh/access/include/access_publish.h
+++ b/mesh/access/include/access_publish.h
@@ -62,7 +62,7 @@ typedef struct __access_model_publication_state_t
     /** Callback called for each publishing event. */
     access_publish_timeout_cb_t publish_timeout_cb;
     /** Target time in units of 100 ms for when the next publishing operation is triggered. */
-    uint32_t target;
+    timestamp_t target;
     /** Pointer to the next publication event. */
     struct __access_model_publication_state_t * p_next;
 } access_model_publication_state_t;
diff --git a/mesh/access/src/access_reliable.c b/mesh/access/src/access_reliable.c
index d16d5d60c..734830c73 100644
--- a/mesh/access/src/access_reliable.c
+++ b/mesh/access/src/access_reliable.c
@@ -280,7 +280,7 @@ static uint32_t calculate_interval(const access_reliable_t * p_message)
 static void add_reliable_message(uint16_t index, const access_reliable_t * p_message)
 {
     NRF_MESH_ASSERT(!m_reliable.pool[index].in_use);
-    uint32_t time_now = timer_now();
+    timestamp_t time_now = timer_now();
     memcpy(&(m_reliable.pool[index].params), p_message, sizeof(access_reliable_t));
     m_reliable.pool[index].interval = calculate_interval(p_message);
     m_reliable.pool[index].params.timeout += time_now;
diff --git a/mesh/bearer/src/adv_ext_tx.c b/mesh/bearer/src/adv_ext_tx.c
index 8165d9af8..f12c515fa 100644
--- a/mesh/bearer/src/adv_ext_tx.c
+++ b/mesh/bearer/src/adv_ext_tx.c
@@ -314,7 +314,7 @@ static void setup_aux(adv_ext_tx_t * p_tx)
     mesh_pa_lna_setup_stop();
 
     /* Verify that we were able to service the TX in time */
-    NRF_MESH_ASSERT(TIMER_OLDER_THAN(ts_timer_now(), txen_trigger_time + m_tx_session.start_time));
+    NRF_MESH_ASSERT(TS_TIMER_OLDER_THAN(ts_timer_now(), txen_trigger_time + m_tx_session.start_time));
 
     if (last_in_chain)
     {
diff --git a/mesh/bearer/src/bearer_handler.c b/mesh/bearer/src/bearer_handler.c
index 831271d51..3d099e926 100644
--- a/mesh/bearer/src/bearer_handler.c
+++ b/mesh/bearer/src/bearer_handler.c
@@ -157,7 +157,7 @@ static void end_handle(void)
 {
     /* Ensure the action didn't last too long: */
     ts_timestamp_t time_now = ts_timer_now();
-    NRF_MESH_ASSERT(TIMER_OLDER_THAN(time_now, m_end_time));
+    NRF_MESH_ASSERT(TS_TIMER_OLDER_THAN(time_now, m_end_time));
 
     timeslot_state_lock(false);
 
diff --git a/mesh/bearer/src/broadcast.c b/mesh/bearer/src/broadcast.c
index 8b7a0ac72..6009b51fe 100644
--- a/mesh/bearer/src/broadcast.c
+++ b/mesh/bearer/src/broadcast.c
@@ -164,7 +164,7 @@ static inline void tx_complete_notify_user(broadcast_t * p_broadcast)
 #if BROADCAST_DEBUG
     p_broadcast->debug.prev_tx_complete_app_time_us = user_cb_time_end - user_cb_time_start;
 #endif
-    NRF_MESH_ASSERT(TIMER_OLDER_THAN(user_cb_time_end, user_cb_time_start + USR_SOFTWARE_OVERHEAD_US));
+    NRF_MESH_ASSERT(TS_TIMER_OLDER_THAN(user_cb_time_end, user_cb_time_start + USR_SOFTWARE_OVERHEAD_US));
 }
 static inline void end_action(broadcast_t * p_broadcast)
 {
diff --git a/mesh/bearer/src/instaburst_rx.c b/mesh/bearer/src/instaburst_rx.c
index a4157bcf5..14c97d0f5 100644
--- a/mesh/bearer/src/instaburst_rx.c
+++ b/mesh/bearer/src/instaburst_rx.c
@@ -271,7 +271,7 @@ static void action_start(ts_timestamp_t start_time, void * p_args)
 
         NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
 
-        if (TIMER_OLDER_THAN(m_instaburst.event.packet.start_time, ts_timer_now() + START_TIME_OVERHEAD_US))
+        if (TS_TIMER_OLDER_THAN(m_instaburst.event.packet.start_time, ts_timer_now() + START_TIME_OVERHEAD_US))
         {
             /* Can't make it in time */
             DEBUG_PIN_INSTABURST_ON(DEBUG_PIN_INSTABURST_TOO_SLOW);
@@ -333,7 +333,7 @@ static void action_start(ts_timestamp_t start_time, void * p_args)
 
             /* Ensure that the timer order above was scheduled in time. If this fails, we were
              * locking IRQs for too long, delaying packet processing. */
-            NRF_MESH_ASSERT(TIMER_OLDER_THAN(ts_timer_now(), rampup_start_time));
+            NRF_MESH_ASSERT(TS_TIMER_OLDER_THAN(ts_timer_now(), rampup_start_time));
         }
     }
     else
diff --git a/mesh/bearer/src/instaburst_tx.c b/mesh/bearer/src/instaburst_tx.c
index 43a6f2c26..d837a057b 100644
--- a/mesh/bearer/src/instaburst_tx.c
+++ b/mesh/bearer/src/instaburst_tx.c
@@ -218,7 +218,7 @@ static bool order_tx(instaburst_tx_t * p_instaburst)
     return did_order;
 }
 
-static void tx_timeout(uint32_t timestamp, void * p_context)
+static void tx_timeout(timestamp_t timestamp, void * p_context)
 {
     instaburst_tx_t * p_instaburst = p_context;
     instaburst_tx_finalize(p_instaburst);
diff --git a/mesh/bearer/src/scanner.c b/mesh/bearer/src/scanner.c
index dbc6c0a29..85cfbc92c 100755
--- a/mesh/bearer/src/scanner.c
+++ b/mesh/bearer/src/scanner.c
@@ -451,13 +451,13 @@ void scanner_timer_irq_handler(void)
 * Timer handling
 *****************************************************************************/
 
-static void scan_window_end(uint32_t timestamp, void * p_context)
+static void scan_window_end(timestamp_t timestamp, void * p_context)
 {
     m_scanner.window_state = SCAN_WINDOW_STATE_OFF;
     radio_trigger();
 }
 
-static void scan_window_start(uint32_t timestamp, void * p_context)
+static void scan_window_start(timestamp_t timestamp, void * p_context)
 {
     channel_iterate();
     radio_trigger();
@@ -465,7 +465,7 @@ static void scan_window_start(uint32_t timestamp, void * p_context)
 
 static void schedule_timers(void)
 {
-    uint32_t time_now = timer_now();
+    timestamp_t time_now = timer_now();
 
     if (continuous_scanning())
     {
diff --git a/mesh/core/CMakeLists.txt b/mesh/core/CMakeLists.txt
index c12244724..f23dde283 100644
--- a/mesh/core/CMakeLists.txt
+++ b/mesh/core/CMakeLists.txt
@@ -18,7 +18,6 @@ set(MESH_CORE_SOURCE_FILES
     "${CMAKE_CURRENT_SOURCE_DIR}/src/aes_cmac.c"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/timer_scheduler.c"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/timer.c"
-    "${CMAKE_CURRENT_SOURCE_DIR}/src/long_timer.c"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/rand.c"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/nrf_mesh_opt.c"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/mesh_opt.c"
diff --git a/mesh/core/include/core_tx.h b/mesh/core/include/core_tx.h
index b17382188..f00c9b1e8 100644
--- a/mesh/core/include/core_tx.h
+++ b/mesh/core/include/core_tx.h
@@ -202,7 +202,7 @@ struct core_tx_bearer
  */
 typedef void (*core_tx_complete_cb_t)(core_tx_role_t role,
                                       uint32_t bearer_index,
-                                      uint32_t timestamp,
+                                      timestamp_t timestamp,
                                       nrf_mesh_tx_token_t token);
 
 /**
@@ -287,7 +287,7 @@ void core_tx_bearer_add(core_tx_bearer_t * p_bearer,
  */
 void core_tx_complete(core_tx_bearer_t * p_bearer,
                       core_tx_role_t role,
-                      uint32_t timestamp,
+                      timestamp_t timestamp,
                       nrf_mesh_tx_token_t token);
 /** @} */
 
diff --git a/mesh/core/include/long_timer.h b/mesh/core/include/long_timer.h
deleted file mode 100644
index 9e008b879..000000000
--- a/mesh/core/include/long_timer.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* Copyright (c) 2010 - 2020, Nordic Semiconductor ASA
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form, except as embedded into a Nordic
- *    Semiconductor ASA integrated circuit in a product or a software update for
- *    such product, must reproduce the above copyright notice, this list of
- *    conditions and the following disclaimer in the documentation and/or other
- *    materials provided with the distribution.
- *
- * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
- *    contributors may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * 4. This software, with or without modification, must only be used with a
- *    Nordic Semiconductor ASA integrated circuit.
- *
- * 5. Any software provided in binary form under this license must not be reverse
- *    engineered, decompiled, modified and/or disassembled.
- *
- * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef LONG_TIMER_H__
-#define LONG_TIMER_H__
-
-#include "timer_scheduler.h"
-
-/**
- * @defgroup LONG_TIMER Long timer
- * Long running timer for the mesh.
- * @{
- */
-
-
-/** Callback function type */
-typedef void (*lt_callback_t)(void * p_context);
-
-/** Long running timer context. */
-typedef struct
-{
-    uint64_t remaining_time_us; /**< Number of microseconds until the timer fires at the previous tick.
-                                     Use @ref lt_remaining_time to get actual value. */
-    lt_callback_t callback;     /**< Callback to call when the timer expires. */
-    void * p_context;           /**< User specified context passed in the callback. */
-    timer_event_t event;        /**< Timer event used to keep track of the remaining time. */
-} long_timer_t;
-
-/**
- * Schedule a long running timer with a delay.
- *
- * The memory associated with the @p p_timer must be valid until the timer either fires or is aborted.
- *
- * @param[in,out] p_timer Timer to schedule. Rescheduling a running timer will cancel its original timeout value.
- * @param[in] callback Callback to call when the timer finishes.
- * @param[in,out] p_context Context to pass to the timer.
- * @param[in] delay_us Delay in microseconds before the timer should fire.
- */
-void lt_schedule(long_timer_t * p_timer, lt_callback_t callback, void * p_context, uint64_t delay_us);
-
-/**
- * Get the time remaining until the timer fires.
- *
- * @param[in] p_timer Timer to check
- *
- * @returns The number of microseconds until the timer fires.
- */
-uint64_t lt_remaining_time_get(const long_timer_t * p_timer);
-
-/**
- * Abort a scheduled timer.
- *
- * The timer callback will not fire, and the memory can safely be freed.
- *
- * @param[in,out] p_timer Timer to abort.
- */
-void lt_abort(long_timer_t * p_timer);
-
-/** @} */
-
-#endif /* LONG_TIMER_H__ */
diff --git a/mesh/core/include/timer.h b/mesh/core/include/timer.h
index c1add46e7..079074273 100644
--- a/mesh/core/include/timer.h
+++ b/mesh/core/include/timer.h
@@ -53,6 +53,12 @@
 /** Get timestamp - ref, including rollover. */
 #define TIMER_DIFF(timestamp, reference) timer_diff(timestamp, reference)
 
+/** The maximum timer value. A user may substract any value from timestamp_t, which may result in
+ * negative value. Due to the nature of unsigned int type, the negative value will wrap around,
+ * which will result in a value greater than UINT64_MAX / 2. Values greater than UINT64_MAX / 2 are
+ * considered as negative. */
+#define TIMER_MAX (UINT64_MAX / 2)
+
 /**
  * Checks whether the given time is older than the reference (occurs before in time).
  *
@@ -64,10 +70,10 @@
  TIMER_OLDER_THAN(t2, t1) => false
  @endverbatim
  */
-#define TIMER_OLDER_THAN(time, ref) (((uint32_t) (time)) - ((uint32_t) (ref)) > UINT32_MAX / 2)
+#define TIMER_OLDER_THAN(time, ref) ((time) - (ref) > TIMER_MAX)
 
 /** Timestamp type for all time-values */
-typedef uint32_t timestamp_t;
+typedef uint64_t timestamp_t;
 
 /** Callback type for callbacks at finished timers */
 typedef void(* timer_callback_t)(timestamp_t);
@@ -82,7 +88,7 @@ typedef void(* timer_callback_t)(timestamp_t);
  */
 static inline timestamp_t timer_diff(timestamp_t time1, timestamp_t time2)
 {
-    if (time1 - time2 > UINT32_MAX / 2)
+    if (TIMER_OLDER_THAN(time1, time2))
     {
         return time2 - time1;
     }
diff --git a/mesh/core/include/timer_scheduler.h b/mesh/core/include/timer_scheduler.h
index d025591b9..7077b9210 100644
--- a/mesh/core/include/timer_scheduler.h
+++ b/mesh/core/include/timer_scheduler.h
@@ -137,6 +137,15 @@ bool timer_sch_is_scheduled(const timer_event_t * p_timer_evt);
  */
 void timer_sch_stop(void);
 
+/**
+ * Get remaining time.
+ *
+ * @param[in] p_timer_evt Timer scheduler event context pointer.
+ *
+ * @returns Remaining time in us.
+ */
+timestamp_t timer_sch_remaining_time_get(const timer_event_t * p_timer_evt);
+
 /** @} */
 
 #endif /* TIMER_SCHEDULER_H__ */
diff --git a/mesh/core/include/timeslot_timer.h b/mesh/core/include/timeslot_timer.h
index 41ad4e55e..db602a5c7 100644
--- a/mesh/core/include/timeslot_timer.h
+++ b/mesh/core/include/timeslot_timer.h
@@ -62,6 +62,9 @@
 /** Timer index for getting timestamps */
 #define TS_TIMER_INDEX_TIMESTAMP   (3)
 
+/** Analogue of TIMER_OLDER_THAN but for ts_timestamp_t. */
+#define TS_TIMER_OLDER_THAN(time, ref) ((time) - (ref) > UINT32_MAX / 2)
+
 /** Timestamp type for time-values based on the timer working within timeslots*/
 typedef uint32_t ts_timestamp_t;
 
diff --git a/mesh/core/src/core_tx.c b/mesh/core/src/core_tx.c
index e160065f0..0bb664631 100644
--- a/mesh/core/src/core_tx.c
+++ b/mesh/core/src/core_tx.c
@@ -194,7 +194,7 @@ uint32_t core_tx_bearer_count_get(void)
 
 void core_tx_complete(core_tx_bearer_t * p_bearer,
                       core_tx_role_t role,
-                      uint32_t timestamp,
+                      timestamp_t timestamp,
                       nrf_mesh_tx_token_t token)
 {
     NRF_MESH_ASSERT(p_bearer);
diff --git a/mesh/core/src/core_tx_instaburst.c b/mesh/core/src/core_tx_instaburst.c
index 0bcad3284..d240231bd 100644
--- a/mesh/core/src/core_tx_instaburst.c
+++ b/mesh/core/src/core_tx_instaburst.c
@@ -72,7 +72,7 @@ static core_tx_bearer_t m_bearer;
 
 static void instaburst_tx_complete_callback(instaburst_tx_t * p_instaburst,
                                             nrf_mesh_tx_token_t token,
-                                            uint32_t timestamp)
+                                            timestamp_t timestamp)
 {
     core_tx_role_t role = (core_tx_role_t) (p_instaburst - &m_instaburst[0]);
     core_tx_complete(&m_bearer, role, timestamp, token);
diff --git a/mesh/core/src/long_timer.c b/mesh/core/src/long_timer.c
deleted file mode 100644
index af2ad0331..000000000
--- a/mesh/core/src/long_timer.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/* Copyright (c) 2010 - 2020, Nordic Semiconductor ASA
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form, except as embedded into a Nordic
- *    Semiconductor ASA integrated circuit in a product or a software update for
- *    such product, must reproduce the above copyright notice, this list of
- *    conditions and the following disclaimer in the documentation and/or other
- *    materials provided with the distribution.
- *
- * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
- *    contributors may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * 4. This software, with or without modification, must only be used with a
- *    Nordic Semiconductor ASA integrated circuit.
- *
- * 5. Any software provided in binary form under this license must not be reverse
- *    engineered, decompiled, modified and/or disassembled.
- *
- * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "long_timer.h"
-#include "utils.h"
-
-#define TIMER_STEP  ((UINT32_MAX / 2) - 1)
-
-static void timer_handler(timestamp_t timestamp, void * p_context)
-{
-    long_timer_t * p_timer = p_context;
-    p_timer->remaining_time_us -= MIN(TIMER_STEP, p_timer->remaining_time_us);
-
-    if (p_timer->remaining_time_us == 0)
-    {
-        p_timer->event.interval = 0;
-        p_timer->callback(p_timer->p_context);
-    }
-    else
-    {
-        p_timer->event.interval = MIN(TIMER_STEP, p_timer->remaining_time_us);
-    }
-}
-
-void lt_schedule(long_timer_t * p_timer, lt_callback_t callback, void * p_context, uint64_t delay_us)
-{
-    p_timer->callback = callback;
-    p_timer->p_context = p_context;
-    p_timer->remaining_time_us = delay_us;
-    p_timer->event.p_context = p_timer;
-    p_timer->event.cb = timer_handler;
-    timer_sch_reschedule(&p_timer->event, timer_now() + MIN(TIMER_STEP, p_timer->remaining_time_us));
-}
-
-void lt_abort(long_timer_t * p_timer)
-{
-    timer_sch_abort(&p_timer->event);
-}
-
-uint64_t lt_remaining_time_get(const long_timer_t * p_timer)
-{
-    timestamp_t diff = timer_diff(timer_now(), p_timer->event.timestamp);
-
-    return p_timer->remaining_time_us > diff ? p_timer->remaining_time_us - diff : 0;
-}
diff --git a/mesh/core/src/lpn.c b/mesh/core/src/lpn.c
index 081355449..f189a0fe1 100644
--- a/mesh/core/src/lpn.c
+++ b/mesh/core/src/lpn.c
@@ -48,7 +48,7 @@
 #include "core_tx_lpn.h"
 #include "transport.h"
 #include "packet_mesh.h"
-#include "long_timer.h"
+#include "timer_scheduler.h"
 #include "utils.h"
 #include "event.h"
 #include "nrf_mesh_assert.h"
@@ -188,7 +188,7 @@ typedef struct
     uint8_t             fsn;
     uint8_t             poll_attempts_count;
     uint8_t             frndreq_attempts_count;
-    long_timer_t        timeout_scheduler;
+    timer_event_t       timeout_scheduler;
     transport_control_packet_t * p_subman_data;
 } lpn_t;
 
@@ -202,10 +202,10 @@ DECLARE_GUARD_PROTOTYPE(GUARD_LIST)
 static void lpn_fsm_action(fsm_action_id_t action_id, void * p_data);
 static bool lpn_fsm_guard(fsm_action_id_t action_id, void * p_data);
 static void lpn_fault_task_post(void);
-static void friend_request_receive_delay_handle(void * p_context);
-static void friend_request_receive_window_handle(void * p_context);
-static void receive_delay_handle(void * p_context);
-static void timeout_handle(void * p_context);
+static void friend_request_receive_delay_handle(timestamp_t timestamp, void * p_context);
+static void friend_request_receive_window_handle(timestamp_t timestamp, void * p_context);
+static void receive_delay_handle(timestamp_t timestamp, void * p_context);
+static void timeout_handle(timestamp_t timestamp, void * p_context);
 static void friend_offer_handle(const transport_control_packet_t * p_control_packet,
                                 const nrf_mesh_rx_metadata_t * p_rx_metadata);
 static void friend_update_handle(const transport_control_packet_t * p_control_packet,
@@ -217,6 +217,8 @@ static void transmit_and_reschedule(const transport_control_packet_t * p_packet,
                                     uint32_t receive_delay_ms,
                                     uint32_t receive_window_ms);
 static void event_send(const nrf_mesh_evt_t * p_evt);
+static void timer_schedule(timer_event_t * p_timer, timer_sch_callback_t callback, void * p_context,
+                           uint64_t delay_us);
 
 static const fsm_transition_t m_lpn_fsm_transition_table[] =
 {
@@ -565,7 +567,7 @@ static void a_poll_schedule(void * p_data)
 {
     fsm_transac_data_t * p_trasac_data = p_data;
 
-    lt_schedule(&m_lpn.timeout_scheduler, timeout_handle, NULL,
+    timer_schedule(&m_lpn.timeout_scheduler, timeout_handle, NULL,
         p_trasac_data != NULL ? MS_TO_US((uint64_t)p_trasac_data->poll_scheduler.delay_ms) : 0ull);
 }
 
@@ -666,7 +668,7 @@ static void friend_update_handle(const transport_control_packet_t * p_control_pa
     fsm_event_post(&m_lpn_fsm, E_FRIEND_UPDATE_RX, &data);
 }
 
-static void friend_request_receive_delay_handle(void * p_context)
+static void friend_request_receive_delay_handle(timestamp_t timestamp, void * p_context)
 {
     uint32_t receive_window_ms = (uint32_t) p_context;
     uint64_t scanning_time_us = SCANNING_TIME_US((uint64_t) receive_window_ms);
@@ -680,20 +682,21 @@ static void friend_request_receive_delay_handle(void * p_context)
     uint32_t remaining_time_ms = MESH_LPN_FRIEND_REQUEST_TIMEOUT_MAX_MS - receive_window_ms;
 
     scanner_enable();
-    lt_schedule(&m_lpn.timeout_scheduler,
-                friend_request_receive_window_handle,
-                (void *) remaining_time_ms,
-                scanning_time_us);
+    timer_schedule(&m_lpn.timeout_scheduler,
+                   friend_request_receive_window_handle,
+                   (void *) remaining_time_ms,
+                   scanning_time_us);
 }
 
-static void friend_request_receive_window_handle(void * p_context)
+static void friend_request_receive_window_handle(timestamp_t timestamp, void * p_context)
 {
     uint32_t remaining_time_ms = (uint32_t) p_context;
 
     scanner_disable();
     if (remaining_time_ms > 0)
     {
-        lt_schedule(&m_lpn.timeout_scheduler, timeout_handle, NULL, MS_TO_US((uint64_t) remaining_time_ms));
+        timer_schedule(&m_lpn.timeout_scheduler, timeout_handle, NULL,
+                       MS_TO_US((uint64_t) remaining_time_ms));
     }
     else
     {
@@ -701,15 +704,16 @@ static void friend_request_receive_window_handle(void * p_context)
     }
 }
 
-static void receive_delay_handle(void * p_context)
+static void receive_delay_handle(timestamp_t timestamp, void * p_context)
 {
     uint32_t receive_window_ms = (uint32_t) p_context;
 
     scanner_enable();
-    lt_schedule(&m_lpn.timeout_scheduler, timeout_handle, NULL, SCANNING_TIME_US((uint64_t) receive_window_ms));
+    timer_schedule(&m_lpn.timeout_scheduler, timeout_handle, NULL,
+                   SCANNING_TIME_US((uint64_t) receive_window_ms));
 }
 
-static void timeout_handle(void * p_context)
+static void timeout_handle(timestamp_t timestamp, void * p_context)
 {
     (void)p_context;
 
@@ -745,26 +749,26 @@ static void transmit_and_reschedule(const transport_control_packet_t * p_packet,
     {
         if (token == NRF_MESH_FRIEND_REQUEST_TOKEN)
         {
-            lt_schedule(&m_lpn.timeout_scheduler,
-                        friend_request_receive_delay_handle,
-                        (void*) receive_window_ms,
-                        MS_TO_US((uint64_t)receive_delay_ms) + TIMER_JITTER_US);
+            timer_schedule(&m_lpn.timeout_scheduler,
+                           friend_request_receive_delay_handle,
+                           (void*) receive_window_ms,
+                           MS_TO_US((uint64_t)receive_delay_ms) + TIMER_JITTER_US);
         }
         else
         {
-            lt_schedule(&m_lpn.timeout_scheduler,
-                        receive_delay_handle,
-                        (void*) receive_window_ms,
-                        MS_TO_US((uint64_t)receive_delay_ms) + TIMER_JITTER_US);
+            timer_schedule(&m_lpn.timeout_scheduler,
+                           receive_delay_handle,
+                           (void*) receive_window_ms,
+                           MS_TO_US((uint64_t)receive_delay_ms) + TIMER_JITTER_US);
         }
     }
     else
     {
         __LOG(LOG_SRC_FSM, LOG_LEVEL_DBG1, "LPN transport TX failed (%u)\n", err_code);
-        lt_schedule(&m_lpn.timeout_scheduler,
-                    timeout_handle,
-                    NULL,
-                    MS_TO_US((uint64_t)receive_delay_ms + receive_window_ms));
+        timer_schedule(&m_lpn.timeout_scheduler,
+                       timeout_handle,
+                       NULL,
+                       MS_TO_US((uint64_t)receive_delay_ms + receive_window_ms));
     }
 }
 
@@ -799,7 +803,7 @@ static void lpn_terminate_task(void)
 {
     fsm_event_post(&m_lpn_fsm, E_TERMINATE, NULL);
 
-    lt_abort(&m_lpn.timeout_scheduler);
+    timer_sch_abort(&m_lpn.timeout_scheduler);
 
     nrf_mesh_evt_t evt;
     termination_evt_prepare(&evt, NRF_MESH_EVT_FRIENDSHIP_TERMINATED_REASON_LPN);
@@ -849,6 +853,15 @@ static bool is_friendship_secmat(const network_packet_metadata_t * p_net_metadat
             (intptr_t) p_frnd_secmat == (intptr_t) p_net_metadata->p_security_material);
 }
 
+static void timer_schedule(timer_event_t * p_timer, timer_sch_callback_t callback, void * p_context,
+                           uint64_t delay_us)
+{
+    p_timer->cb = callback;
+    p_timer->p_context = p_context;
+    p_timer->interval = 0ul;
+    timer_sch_reschedule(p_timer, timer_now() + delay_us);
+}
+
 /******************************* API *****************************************/
 void mesh_lpn_init(void)
 {
diff --git a/mesh/core/src/timer.c b/mesh/core/src/timer.c
index 949fef547..2d4e8b5e9 100644
--- a/mesh/core/src/timer.c
+++ b/mesh/core/src/timer.c
@@ -52,12 +52,12 @@
 #define PROTECTION_MARGIN_FOR_OVFW_HANDLER  2ul
 
 #define TIMER_US_TO_TICKS(US)                              \
-            ((uint32_t)ROUNDED_DIV(                        \
+            (ROUNDED_DIV(                                  \
             (US) * (uint64_t)APP_TIMER_CLOCK_FREQ,         \
             1000000ull * (APP_TIMER_CONFIG_RTC_FREQUENCY + 1)))
 
 #define TIMER_TICKS_TO_US(TICKS)                                         \
-            ((uint32_t)ROUNDED_DIV(                                      \
+            (ROUNDED_DIV(                                                \
             (TICKS) * 1000000ull * (APP_TIMER_CONFIG_RTC_FREQUENCY + 1), \
             APP_TIMER_CLOCK_FREQ))
 
@@ -122,7 +122,7 @@ void timer_init(void)
 timestamp_t timer_now(void)
 {
     uint32_t was_masked;
-    uint32_t ovfw_counter;
+    uint64_t ovfw_counter;
     uint32_t sample;
 
     _DISABLE_IRQS(was_masked);
@@ -153,7 +153,7 @@ void timer_start(timestamp_t timestamp, timer_callback_t cb)
         time_diff = timestamp - time_now;
     }
 
-    uint32_t timeout_ticks = TIMER_US_TO_TICKS(time_diff);
+    uint64_t timeout_ticks = TIMER_US_TO_TICKS(time_diff);
 
     _DISABLE_IRQS(was_masked);
     uint32_t ticks_now = NRF_RTC1->COUNTER;
diff --git a/mesh/core/src/timer_scheduler.c b/mesh/core/src/timer_scheduler.c
index 6b1e9ec15..76c22fd8d 100644
--- a/mesh/core/src/timer_scheduler.c
+++ b/mesh/core/src/timer_scheduler.c
@@ -236,3 +236,16 @@ void timer_sch_stop(void)
     m_scheduler.p_head = NULL;
     timer_stop();
 }
+
+timestamp_t timer_sch_remaining_time_get(const timer_event_t * p_timer_evt)
+{
+    timestamp_t time_now = timer_now();
+    timestamp_t diff = 0;
+
+    if (TIMER_OLDER_THAN(time_now, p_timer_evt->timestamp))
+    {
+        diff = timer_diff(time_now, p_timer_evt->timestamp);
+    }
+
+    return diff;
+}
diff --git a/mesh/core/src/timeslot_timer.c b/mesh/core/src/timeslot_timer.c
index a069e663e..71602d11c 100644
--- a/mesh/core/src/timeslot_timer.c
+++ b/mesh/core/src/timeslot_timer.c
@@ -53,7 +53,7 @@
 * Static globals
 *****************************************************************************/
 /** Array of function pointers for callbacks for each timer. */
-static timer_callback_t m_callbacks[TIMER_COMPARE_COUNT];
+static ts_timer_callback_t m_callbacks[TIMER_COMPARE_COUNT];
 /** Array of PPI tasks to trigger on timeout. */
 static uint32_t*        mp_ppi_tasks[TIMER_COMPARE_COUNT];
 /** Time captured at the beginning of the current timeslot. */
diff --git a/mesh/core/src/transport.c b/mesh/core/src/transport.c
index e0f289c99..02fe10104 100644
--- a/mesh/core/src/transport.c
+++ b/mesh/core/src/transport.c
@@ -531,7 +531,7 @@ static void tx_retry_timer_reset(trs_sar_ctx_t * p_sar_ctx)
 {
     NRF_MESH_ASSERT(p_sar_ctx->session.session_type == TRS_SAR_SESSION_TX);
 
-    uint32_t next_timeout = timer_now();
+    timestamp_t next_timeout = timer_now();
 
     /* For non-unicast addresses, we're not going to get any acknowledgements, so there's no
      * point in scaling the retry interval according to TTL. */
@@ -1855,7 +1855,7 @@ static void abort_timeout(timestamp_t timestamp, void * p_context)
     sar_ctx_cancel(p_sar_ctx, NRF_MESH_SAR_CANCEL_REASON_TIMEOUT);
 }
 
-static void tx_complete(core_tx_role_t role, uint32_t bearer_index, uint32_t timestamp, nrf_mesh_tx_token_t token)
+static void tx_complete(core_tx_role_t role, uint32_t bearer_index, timestamp_t timestamp, nrf_mesh_tx_token_t token)
 {
     if (role == CORE_TX_ROLE_ORIGINATOR && token != NRF_MESH_SAR_TOKEN)
     {
diff --git a/mesh/dfu/src/nrf_mesh_dfu.c b/mesh/dfu/src/nrf_mesh_dfu.c
index 5e9bdb070..49fde514b 100644
--- a/mesh/dfu/src/nrf_mesh_dfu.c
+++ b/mesh/dfu/src/nrf_mesh_dfu.c
@@ -82,7 +82,7 @@ NRF_MESH_STATIC_ASSERT(NRF_MESH_DFU_ROLE__LAST      <= UINT8_MAX);
  * periodic transmit gets its own slot. */
 typedef struct
 {
-    uint32_t order_time;                    /**< Timestamp when the packet was first ordered. */
+    timestamp_t order_time;                 /**< Timestamp when the packet was first ordered. */
     uint16_t tx_randomization_offset_us;    /**< Randomized time deviation from the normal for the next transmission. */
     bl_radio_interval_type_t interval_type; /**< Type of interval for this periodic transmit. */
     nrf_mesh_dfu_packet_t dfu_packet;       /**< DFU packet being sent on this slot. */
@@ -196,7 +196,7 @@ static uint32_t get_curr_fwid(nrf_mesh_dfu_type_t type, nrf_mesh_fwid_t* p_fwid)
     return NRF_SUCCESS;
 }
 
-static uint32_t next_tx_timeout(dfu_tx_t* p_tx)
+static timestamp_t next_tx_timeout(dfu_tx_t* p_tx)
 {
     switch (p_tx->interval_type)
     {
@@ -285,14 +285,14 @@ static void tx_timeout_handled(dfu_tx_t * p_tx)
     }
 }
 
-static void tx_timeout(uint32_t timestamp, void* p_context)
+static void tx_timeout(timestamp_t timestamp, void* p_context)
 {
-    uint32_t next_timeout = timestamp + (UINT32_MAX / 2);
+    timestamp_t next_timeout = timestamp + (UINT32_MAX / 2);
     for (uint32_t i = 0; i < NRF_MESH_DFU_TX_SLOTS; ++i)
     {
         if (tx_slot_in_use(&m_tx_slots[i]))
         {
-            uint32_t timeout = next_tx_timeout(&m_tx_slots[i]);
+            timestamp_t timeout = next_tx_timeout(&m_tx_slots[i]);
             if (TIMER_OLDER_THAN(timeout, (timestamp + DFU_TX_TIMER_MARGIN_US)))
             {
                 if (m_tx_slots[i].rx_count >= DFU_TX_REDUNDANCY_MAX)
@@ -320,9 +320,9 @@ static void tx_timeout(uint32_t timestamp, void* p_context)
     timer_sch_reschedule(&m_tx_timer_evt, next_timeout);
 }
 
-static void abort_timeout(uint32_t timestamp, void* p_context)
+static void abort_timeout(timestamp_t timestamp, void* p_context)
 {
-    __LOG(LOG_SRC_DFU, LOG_LEVEL_INFO, "ABORT Timeout fired @%d\n", timestamp);
+    __LOG(LOG_SRC_DFU, LOG_LEVEL_INFO, "ABORT Timeout fired @%lu\n", timestamp);
     bl_cmd_t abort_cmd;
     abort_cmd.type = BL_CMD_TYPE_DFU_ABORT;
     if (nrf_mesh_dfu_cmd_send(&abort_cmd) == NRF_SUCCESS)
@@ -331,9 +331,9 @@ static void abort_timeout(uint32_t timestamp, void* p_context)
     }
 }
 
-static void timer_timeout(uint32_t timestamp, void* p_context)
+static void timer_timeout(timestamp_t timestamp, void* p_context)
 {
-    __LOG(LOG_SRC_DFU, LOG_LEVEL_INFO, "Timeout fired @%d\n", timestamp);
+    __LOG(LOG_SRC_DFU, LOG_LEVEL_INFO, "Timeout fired @%lu\n", timestamp);
     bl_cmd_t timeout_cmd;
     timeout_cmd.type = BL_CMD_TYPE_TIMEOUT;
     timeout_cmd.params.timeout.timer_index = 0;
@@ -567,7 +567,7 @@ static uint32_t dfu_evt_handler(const bl_evt_t* p_evt)
                 /* Disable the slot */
                 p_tx_slot->repeats = 0;
 
-                uint32_t time_now = timer_now();
+                timestamp_t time_now = timer_now();
 
                 /* Fill the TX slot. */
                 p_tx_slot->interval_type = p_evt->params.tx.radio.interval_type;
@@ -673,7 +673,7 @@ static uint32_t dfu_cmd_handler_set(bl_if_cmd_handler_t handler)
 }
 #endif
 
-static void tx_complete_cb(broadcast_params_t * p_broadcast, uint32_t timestamp)
+static void tx_complete_cb(broadcast_params_t * p_broadcast, timestamp_t timestamp)
 {
     /* Do nothing */
 }
diff --git a/mesh/friend/src/friend.c b/mesh/friend/src/friend.c
index caa570cb9..362b6e6d1 100644
--- a/mesh/friend/src/friend.c
+++ b/mesh/friend/src/friend.c
@@ -58,7 +58,7 @@
 
 #include "friend_queue.h"
 #include "friend_sublist.h"
-#include "long_timer.h"
+#include "timer_scheduler.h"
 #include "core_tx_friend.h"
 #include "log.h"
 
@@ -96,8 +96,8 @@ typedef struct
     uint8_t fsn;                      /**< Friend Sequence Number. */
     friend_queue_t queue;             /**< Friend queue.  */
     friend_sublist_t sublist;         /**< Subscription list of the LPN. */
-    long_timer_t poll_timeout;        /**< Poll timeout timer. */
-    long_timer_t clear_repeat_timer;  /**< Friend clear repeat timer. */
+    timer_event_t poll_timeout;       /**< Poll timeout timer. */
+    timer_event_t clear_repeat_timer; /**< Friend clear repeat timer. */
     uint8_t clear_repeat_count;       /**< Number of times to send the friend clear message. */
     core_tx_friend_t bearer;          /**< Bearer instance. */
 } friendship_t;
@@ -107,7 +107,7 @@ typedef struct
     uint16_t last_lpn;                /**< Address of the recently seen LPN. */
     uint16_t last_req_count;          /**< Value of the LPN counter received in the friend request. */
     nrf_mesh_tx_token_t token;        /**< Bearer TX token. */
-    long_timer_t confirm_send_timer;  /**< Respond to valid Friend clear message in this period. */
+    timer_event_t confirm_send_timer; /**< Respond to valid Friend clear message in this period. */
 } recent_lpns_t;
 
 typedef struct
@@ -126,9 +126,9 @@ typedef struct
 /*****************************************************************************
 * Static function declarations
 *****************************************************************************/
-static void poll_timeout_cb(void * p_context);
-static void friend_clear_timeout_cb(void * p_context);
-static void confirm_send_timer_cb(void * p_context);
+static void poll_timeout_cb(timestamp_t timestamp, void * p_context);
+static void friend_clear_timeout_cb(timestamp_t timestamp, void * p_context);
+static void confirm_send_timer_cb(timestamp_t timestamp, void * p_context);
 
 /*****************************************************************************
 * Static globals
@@ -187,6 +187,14 @@ MESH_CONFIG_ENTRY(mesh_opt_friend,
 
 /* Utility functions */
 
+static void timer_schedule(timer_event_t * p_timer, timer_sch_callback_t callback, void * p_context, uint64_t delay_us)
+{
+    p_timer->cb = callback;
+    p_timer->p_context = p_context;
+    p_timer->interval = 0ul;
+    timer_sch_reschedule(p_timer, timer_now() + delay_us);
+}
+
 /* Find entry matching with given LPN address */
 static uint32_t confirm_timer_entry_find(uint16_t lpn_addr)
 {
@@ -206,7 +214,7 @@ static uint32_t confirm_timer_entry_find(uint16_t lpn_addr)
 /* Find empty entry, and if not found, then nearest expiring entry. */
 static uint32_t confirm_timer_entry_get(void)
 {
-    uint64_t lowest_remaining_time_us = UINT64_MAX;
+    uint64_t lowest_remaining_time_us = TIMER_MAX;
     uint32_t idx = 0;
 
     for (uint32_t i = 0; i < FRIEND_RECENT_LPNS_LIST_COUNT; i++)
@@ -218,7 +226,8 @@ static uint32_t confirm_timer_entry_get(void)
         }
         else
         {
-            uint64_t current_remaining_time_us = lt_remaining_time_get(&m_friend.recent_lpns[i].confirm_send_timer);
+            timestamp_t current_remaining_time_us = timer_sch_remaining_time_get(
+                &m_friend.recent_lpns[i].confirm_send_timer);
 
             if (current_remaining_time_us < lowest_remaining_time_us)
             {
@@ -247,7 +256,7 @@ static void confirm_timer_add(uint16_t lpn_addr, uint32_t poll_timeout_ms, uint3
           lpn_addr, poll_timeout_ms, entry);
     m_friend.recent_lpns[entry].last_lpn = lpn_addr;
     m_friend.recent_lpns[entry].last_req_count = req_count;
-    lt_schedule(&m_friend.recent_lpns[entry].confirm_send_timer,
+    timer_schedule(&m_friend.recent_lpns[entry].confirm_send_timer,
                 confirm_send_timer_cb,
                 &m_friend.recent_lpns[entry],
                 MS_TO_US((uint64_t)poll_timeout_ms));
@@ -262,7 +271,7 @@ static void confirm_timer_clear(uint16_t lpn_addr)
         {
             __LOG(LOG_SRC_FRIEND, LOG_LEVEL_DBG1, "Cleared\n");
             m_friend.recent_lpns[i].last_lpn = NRF_MESH_ADDR_UNASSIGNED;
-            lt_abort(&m_friend.recent_lpns[i].confirm_send_timer);
+            timer_sch_abort(&m_friend.recent_lpns[i].confirm_send_timer);
         }
     }
 }
@@ -333,7 +342,7 @@ static void friendship_state_reset(friendship_t * p_friendship)
     core_tx_friend_disable(&p_friendship->bearer);
     friend_queue_clear(&p_friendship->queue);
     friend_sublist_clear(&p_friendship->sublist);
-    lt_abort(&p_friendship->poll_timeout);
+    timer_sch_abort(&p_friendship->poll_timeout);
 }
 
 static void friendship_terminate(friendship_t * p_friendship,
@@ -413,13 +422,13 @@ static friendship_t * friendship_find(uint16_t lpn_address)
 static void poll_timeout_schedule(friendship_t * p_friendship, timestamp_t rx_timestamp, uint64_t poll_timeout_us)
 {
     timestamp_t diff = timer_now() - rx_timestamp;
-    lt_schedule(&p_friendship->poll_timeout, poll_timeout_cb, p_friendship,
+    timer_schedule(&p_friendship->poll_timeout, poll_timeout_cb, p_friendship,
                 diff < poll_timeout_us ? poll_timeout_us - diff : 0);
 }
 
 static void friend_clear_timeout_schedule(friendship_t * p_friendship, uint64_t clear_repeat_timeout_us)
 {
-    lt_schedule(&p_friendship->clear_repeat_timer, friend_clear_timeout_cb, p_friendship, clear_repeat_timeout_us);
+    timer_schedule(&p_friendship->clear_repeat_timer, friend_clear_timeout_cb, p_friendship, clear_repeat_timeout_us);
 }
 
 static friendship_t * free_friendship_context_get(void)
@@ -693,7 +702,7 @@ static void friend_clear_confirm_tx(uint16_t lpn_src, uint16_t lpn_req_count,
                           status == NRF_ERROR_FORBIDDEN);
 }
 
-static void poll_timeout_cb(void * p_context)
+static void poll_timeout_cb(timestamp_t timestamp, void * p_context)
 {
     NRF_MESH_ASSERT_DEBUG(p_context != NULL);
     friendship_t * p_friendship = p_context;
@@ -702,7 +711,7 @@ static void poll_timeout_cb(void * p_context)
                          NRF_MESH_EVT_FRIENDSHIP_TERMINATED_REASON_TIMEOUT);
 }
 
-static void friend_clear_timeout_cb(void * p_context)
+static void friend_clear_timeout_cb(timestamp_t timestamp, void * p_context)
 {
     friendship_t * p_friendship = p_context;
 
@@ -717,7 +726,7 @@ static void friend_clear_timeout_cb(void * p_context)
     }
 }
 
-static void confirm_send_timer_cb(void * p_context)
+static void confirm_send_timer_cb(timestamp_t timestamp, void * p_context)
 {
     recent_lpns_t * p_recent_lpns = p_context;
     __LOG(LOG_SRC_FRIEND, LOG_LEVEL_DBG1, "Removing last seen LPN: 0x%04x\n", p_recent_lpns->last_lpn);
@@ -1044,7 +1053,7 @@ static void friend_clear_confirm_handle(const transport_control_packet_t * p_con
         return;
     }
 
-    lt_abort(&p_friendship->clear_repeat_timer);
+    timer_sch_abort(&p_friendship->clear_repeat_timer);
 }
 
 static void friend_sublist_add_handle(const transport_control_packet_t * p_control_packet,
@@ -1578,7 +1587,8 @@ uint32_t friend_remaining_poll_timeout_time_get(uint16_t src)
     friendship_t * p_friendship = friendship_find(src);
     if (p_friendship != NULL)
     {
-        return ROUNDED_DIV(US_TO_MS(lt_remaining_time_get(&p_friendship->poll_timeout)), 100);
+        timestamp_t remaining_time = timer_sch_remaining_time_get(&p_friendship->poll_timeout);
+        return ROUNDED_DIV(US_TO_MS(remaining_time), 100);
     }
     else
     {
diff --git a/mesh/prov/src/prov_bearer_adv.c b/mesh/prov/src/prov_bearer_adv.c
index 9f4f583b0..d89a04bb3 100644
--- a/mesh/prov/src/prov_bearer_adv.c
+++ b/mesh/prov/src/prov_bearer_adv.c
@@ -1239,7 +1239,7 @@ static uint32_t prov_bearer_adv_tx(prov_bearer_t * p_bearer, const uint8_t * p_d
     reset_timeout_timer(p_pb_adv);
 
     /* Add the time we'll spend transmitting the packets to the retry interval. */
-    uint32_t time_now = timer_now();
+    timestamp_t time_now = timer_now();
     uint32_t retry_interval = PROV_BEARER_ADV_TRANSACTION_BASE_RETRY_INTERVAL_US
         + (transaction_total_segment_count_get(length) * p_pb_adv->advertiser.config.advertisement_interval_us);
     p_pb_adv->timeout_event.interval = retry_interval;
diff --git a/mesh/test/CMakeLists.txt b/mesh/test/CMakeLists.txt
index 1e76ecc83..591ad3a2d 100644
--- a/mesh/test/CMakeLists.txt
+++ b/mesh/test/CMakeLists.txt
@@ -1375,7 +1375,7 @@ set(lpn_srcs
     ../core/src/log.c
     ${CMOCK_BIN}/transport_mock.c
     ${CMOCK_BIN}/bearer_event_mock.c
-    ${CMOCK_BIN}/long_timer_mock.c
+    ${CMOCK_BIN}/timer_scheduler_mock.c
     ${CMOCK_BIN}/scanner_mock.c
     ${CMOCK_BIN}/event_mock.c
     ${CMOCK_BIN}/nrf_mesh_externs_mock.c
@@ -1429,7 +1429,7 @@ set(friend_srcs
     ${CMOCK_BIN}/event_mock.c
     ${CMOCK_BIN}/net_state_mock.c
     ${CMOCK_BIN}/device_state_manager_mock.c
-    ${CMOCK_BIN}/long_timer_mock.c)
+    ${CMOCK_BIN}/timer_scheduler_mock.c)
 add_unit_test(friend "${friend_srcs}" "${include_directories}" "${compile_options};-DMESH_FEATURE_FRIEND_ENABLED")
 
 set(friend_sublist_test_srcs
@@ -1545,14 +1545,6 @@ set(scene_server_srcs
     )
 add_unit_test(scene_server "${scene_server_srcs}" "${include_directories}" "${compile_options};-DNRF52;-DSCENE_SETUP_SERVER_INSTANCES_MAX=1")
 
-set(long_timer_srcs
-    src/ut_long_timer.c
-    ../core/src/long_timer.c
-    ${CMOCK_BIN}/timer_scheduler_mock.c
-    ${CMOCK_BIN}/timer_mock.c
-    )
-add_unit_test(long_timer "${long_timer_srcs}" "${include_directories}" "${compile_options}")
-
 set(emergency_cache_srcs
     src/ut_emergency_cache.c
     ../core/src/emergency_cache.c
diff --git a/mesh/test/src/proxy_test_common.c b/mesh/test/src/proxy_test_common.c
index 4ed092aed..778f0fc9a 100644
--- a/mesh/test/src/proxy_test_common.c
+++ b/mesh/test/src/proxy_test_common.c
@@ -218,7 +218,7 @@ void core_tx_bearer_add(core_tx_bearer_t * p_bearer,
 
 void core_tx_complete(core_tx_bearer_t * p_bearer,
                       core_tx_role_t role,
-                      uint32_t timestamp,
+                      timestamp_t timestamp,
                       nrf_mesh_tx_token_t token)
 {
 
diff --git a/mesh/test/src/ut_core_tx.c b/mesh/test/src/ut_core_tx.c
index 225bf2cff..2b38536b8 100644
--- a/mesh/test/src/ut_core_tx.c
+++ b/mesh/test/src/ut_core_tx.c
@@ -154,7 +154,7 @@ struct
 
 void tx_complete_cb(core_tx_role_t role,
                     uint32_t bearer_index,
-                    uint32_t timestamp,
+                    timestamp_t timestamp,
                     nrf_mesh_tx_token_t token)
 {
     TEST_ASSERT_TRUE(m_tx_complete_expect.calls > 0);
diff --git a/mesh/test/src/ut_friend.c b/mesh/test/src/ut_friend.c
index db8b685ab..75e6d6811 100644
--- a/mesh/test/src/ut_friend.c
+++ b/mesh/test/src/ut_friend.c
@@ -54,7 +54,7 @@
 #include "test_assert.h"
 #include "mesh_opt_core_mock.h"
 #include "device_state_manager_mock.h"
-#include "long_timer_mock.h"
+#include "timer_scheduler_mock.h"
 
 #include "mesh_opt_friend.h"
 #include "log.h"
@@ -89,7 +89,7 @@ static nrf_mesh_network_secmat_t m_friend_secmat;
 static uint16_t m_friend_counter;
 static uint16_t m_lpn_src = LPN_SRC;
 static uint32_t m_time_now;
-static long_timer_t * mp_confirm_send_timer;
+static timer_event_t * mp_confirm_send_timer;
 static nrf_mesh_rx_metadata_t m_rx_metadata;
 static network_tx_packet_buffer_t m_net_buf;
 static uint8_t m_trs_pdu[PACKET_MESH_TRS_UNSEG_ACCESS_MAX_SIZE];
@@ -175,11 +175,11 @@ static void event_handle_stub(const nrf_mesh_evt_t * p_evt,
     TEST_ASSERT_EQUAL_nrf_mesh_evt_t(expected, (*p_evt));
 }
 
-uint64_t lt_remaining_time_get_stub(const long_timer_t * p_timer, int num_calls)
+timestamp_t timer_sch_remaining_time_get_stub(const timer_event_t * p_timer_evt, int num_calls)
 {
-    TEST_ASSERT_NOT_NULL(p_timer);
+    TEST_ASSERT_NOT_NULL(p_timer_evt);
 
-    return p_timer->remaining_time_us;
+    return p_timer_evt->timestamp - timer_now();
 }
 
 static void unicast_address_get_Expect(void)
@@ -241,20 +241,19 @@ timestamp_t timer_now(void)
     return m_time_now;
 }
 
-static void lt_schedule_stub_cb(long_timer_t * p_timer, lt_callback_t callback, void * p_context, uint64_t delay_us, int num)
+static void timer_sch_reschedule_stub_cb(timer_event_t* p_timer_evt, timestamp_t new_timeout, int num)
 {
-    TEST_ASSERT(p_timer != NULL);
-    TEST_ASSERT(callback != NULL);
-    TEST_ASSERT(p_context != NULL);
+    TEST_ASSERT(p_timer_evt != NULL);
+    TEST_ASSERT(p_timer_evt->cb != NULL);
+    TEST_ASSERT(p_timer_evt->p_context != NULL);
 
-    mp_confirm_send_timer = p_timer;
-    mp_confirm_send_timer->callback = callback;
-    mp_confirm_send_timer->p_context = p_context;
+    mp_confirm_send_timer = p_timer_evt;
+    p_timer_evt->timestamp = new_timeout;
 }
 
-static void timer_trigger(long_timer_t * p_timer)
+static void timer_trigger(timer_event_t * p_timer)
 {
-    p_timer->callback(p_timer->p_context);
+    p_timer->cb(p_timer->timestamp, p_timer->p_context);
 }
 
 static void friend_rx(transport_control_opcode_t opcode,
@@ -355,10 +354,14 @@ static void friend_request_Receive(uint16_t prev_address, uint16_t dst)
 static void poll_timeout_schedule_Expect(timestamp_t rx_timestamp, uint32_t timeout_us)
 {
     timestamp_t diff = timer_now() - rx_timestamp;
-    lt_schedule_Expect(NULL, NULL, NULL, diff < timeout_us ? timeout_us - diff : 0);
-    lt_schedule_IgnoreArg_p_timer();
-    lt_schedule_IgnoreArg_callback();
-    lt_schedule_IgnoreArg_p_context();
+    timestamp_t expect = timer_now();
+
+    if (diff < timeout_us) {
+        expect += timeout_us - diff;
+    }
+
+    timer_sch_reschedule_Expect(NULL, expect);
+    timer_sch_reschedule_IgnoreArg_p_timer_evt();
 }
 
 static uint32_t network_packet_alloc_stub(network_tx_packet_buffer_t * p_buf,
@@ -527,7 +530,7 @@ static void friendship_state_reset_Expect(void)
 {
     core_tx_friend_disable_ExpectAnyArgs();
     friend_sublist_clear_ExpectAnyArgs();
-    lt_abort_ExpectAnyArgs();
+    timer_sch_abort_ExpectAnyArgs();
 }
 
 static void friendship_terminated_event_Expect(void)
@@ -560,7 +563,7 @@ static void friendship_Terminate(void)
     const mesh_friendship_t * p_friendships[MESH_FRIEND_FRIENDSHIP_COUNT];
     uint8_t count = MESH_FRIEND_FRIENDSHIP_COUNT;
     TEST_ASSERT_EQUAL(NRF_SUCCESS, mesh_friend_friendships_get(&p_friendships[0], &count));
-    lt_schedule_StubWithCallback(lt_schedule_stub_cb);
+    timer_sch_reschedule_StubWithCallback(timer_sch_reschedule_stub_cb);
     TEST_ASSERT_EQUAL(NRF_SUCCESS, mesh_friend_friendship_terminate(p_friendships[0]));
 }
 
@@ -572,7 +575,7 @@ static void friendship_Terminate_by_friend_clear(void)
     const mesh_friendship_t * p_friendships[MESH_FRIEND_FRIENDSHIP_COUNT];
     uint8_t count = MESH_FRIEND_FRIENDSHIP_COUNT;
     TEST_ASSERT_EQUAL(NRF_SUCCESS, mesh_friend_friendships_get(&p_friendships[0], &count));
-    lt_schedule_StubWithCallback(lt_schedule_stub_cb);
+    timer_sch_reschedule_StubWithCallback(timer_sch_reschedule_stub_cb);
     friend_clear_confirm_Expect(p_friendships[0]->lpn.src, p_friendships[0]->lpn.request_count);
 
     friend_clear_Receive(p_friendships[0]->lpn.src, p_friendships[0]->lpn.request_count);
@@ -602,7 +605,7 @@ void setUp(void)
     event_queue_Init();
     nrf_mesh_events_mock_Init();
     device_state_manager_mock_Init();
-    long_timer_mock_Init();
+    timer_scheduler_mock_Init();
 
     __LOG_INIT(0xFFFFFFFF, LOG_LEVEL_DBG3, LOG_CALLBACK_DEFAULT);
 
@@ -671,8 +674,8 @@ void tearDown(void)
     nrf_mesh_events_mock_Destroy();
     device_state_manager_mock_Verify();
     device_state_manager_mock_Destroy();
-    long_timer_mock_Verify();
-    long_timer_mock_Destroy();
+    timer_scheduler_mock_Verify();
+    timer_scheduler_mock_Destroy();
 }
 
 /*******************************************************************************
@@ -919,7 +922,7 @@ void test_confirm_send_timer(void)
     uint32_t i;
 
     /* Last termination should over-write the first entry (corresponding to LPN_SRC) */
-    lt_remaining_time_get_StubWithCallback(lt_remaining_time_get_stub);
+    timer_sch_remaining_time_get_StubWithCallback(timer_sch_remaining_time_get_stub);
     for (i = 0; i < (FRIEND_RECENT_LPNS_LIST_COUNT + 1); i++)
     {
         friendship_Establish();
diff --git a/mesh/test/src/ut_long_timer.c b/mesh/test/src/ut_long_timer.c
deleted file mode 100644
index 812e40a7c..000000000
--- a/mesh/test/src/ut_long_timer.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/* Copyright (c) 2010 - 2020, Nordic Semiconductor ASA
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form, except as embedded into a Nordic
- *    Semiconductor ASA integrated circuit in a product or a software update for
- *    such product, must reproduce the above copyright notice, this list of
- *    conditions and the following disclaimer in the documentation and/or other
- *    materials provided with the distribution.
- *
- * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
- *    contributors may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * 4. This software, with or without modification, must only be used with a
- *    Nordic Semiconductor ASA integrated circuit.
- *
- * 5. Any software provided in binary form under this license must not be reverse
- *    engineered, decompiled, modified and/or disassembled.
- *
- * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "long_timer.h"
-
-#include <stddef.h>
-#include <unity.h>
-#include "utils.h"
-
-#include "timer_scheduler_mock.h"
-#include "timer_mock.h"
-
-#define TIMER_STEP  ((UINT32_MAX / 2) - 1)
-#define TIME_NOW    (0x2a)
-
-static long_timer_t m_timer;
-static bool m_is_cb_expected;
-
-void setUp(void)
-{
-    timer_scheduler_mock_Init();
-    timer_mock_Init();
-}
-
-void tearDown(void)
-{
-    timer_scheduler_mock_Verify();
-    timer_scheduler_mock_Destroy();
-    timer_mock_Verify();
-    timer_mock_Destroy();
-}
-
-static void lt_cb(void * p_context)
-{
-    TEST_ASSERT_EQUAL(m_timer.p_context, p_context);
-    TEST_ASSERT_TRUE(m_is_cb_expected);
-    m_is_cb_expected = false;
-}
-
-static void single_timer_schedule(uint64_t time)
-{
-    timer_now_ExpectAndReturn(TIME_NOW);
-    timer_sch_reschedule_Expect(&m_timer.event, TIME_NOW + MIN(TIMER_STEP, time));
-    lt_schedule(&m_timer, lt_cb, single_timer_schedule, time);
-
-    TEST_ASSERT_EQUAL(m_timer.callback, lt_cb);
-    TEST_ASSERT_EQUAL(m_timer.p_context, single_timer_schedule);
-    TEST_ASSERT_EQUAL(m_timer.remaining_time_us, time);
-    TEST_ASSERT_EQUAL(m_timer.event.p_context, &m_timer);
-    TEST_ASSERT_NOT_NULL(m_timer.event.cb);
-}
-
-static void timer_handler_rounds(uint64_t rounds)
-{
-    uint64_t remaining_time_us = m_timer.remaining_time_us;
-
-    while (rounds != 0)
-    {
-        remaining_time_us -= MIN(TIMER_STEP, remaining_time_us);
-
-        if (rounds == 1)
-        {
-            m_is_cb_expected = true;
-        }
-        m_timer.event.cb(0, (void *)&m_timer);
-
-        rounds--;
-        TEST_ASSERT_EQUAL(remaining_time_us, m_timer.remaining_time_us);
-        TEST_ASSERT_EQUAL(rounds == 0 ? 0 : MIN(TIMER_STEP, remaining_time_us), m_timer.event.interval);
-    }
-
-    TEST_ASSERT_EQUAL(0, remaining_time_us);
-}
-
-void test_lt_schedule(void)
-{
-    single_timer_schedule(TIMER_STEP - 1);
-    single_timer_schedule(TIMER_STEP + 1);
-}
-
-void test_lt_timer_handler(void)
-{
-    single_timer_schedule(0);
-    timer_handler_rounds(CEIL_DIV(0, TIMER_STEP));
-
-    single_timer_schedule(TIMER_STEP);
-    timer_handler_rounds(CEIL_DIV(TIMER_STEP, TIMER_STEP));
-
-    single_timer_schedule(TIMER_STEP + 1);
-    timer_handler_rounds(CEIL_DIV(TIMER_STEP + 1, TIMER_STEP));
-
-    single_timer_schedule(100ull * TIMER_STEP + 42);
-    timer_handler_rounds(CEIL_DIV(100ull * TIMER_STEP + 42, TIMER_STEP));
-}
-
-void test_lt_abort(void)
-{
-    timer_sch_abort_Expect(&m_timer.event);
-    lt_abort(&m_timer);
-}
-
-void test_lt_remaining_time_get(void)
-{
-    single_timer_schedule(0);
-    timer_now_ExpectAndReturn(TIME_NOW);
-    m_timer.event.timestamp = TIME_NOW;
-    TEST_ASSERT_EQUAL(0, lt_remaining_time_get(&m_timer));
-
-    single_timer_schedule(TIMER_STEP);
-    m_timer.event.timestamp = TIME_NOW;
-    timer_now_ExpectAndReturn(2 * TIME_NOW);
-    TEST_ASSERT_EQUAL(TIMER_STEP - TIME_NOW, lt_remaining_time_get(&m_timer));
-}
diff --git a/mesh/test/src/ut_lpn.c b/mesh/test/src/ut_lpn.c
index 97c18e30b..128ce14e1 100644
--- a/mesh/test/src/ut_lpn.c
+++ b/mesh/test/src/ut_lpn.c
@@ -45,7 +45,7 @@
 
 #include "transport_mock.h"
 #include "bearer_event_mock.h"
-#include "long_timer_mock.h"
+#include "timer_scheduler_mock.h"
 #include "scanner_mock.h"
 #include "event_mock.h"
 #include "nrf_mesh_externs_mock.h"
@@ -54,7 +54,7 @@ void setUp(void)
 {
     transport_mock_Init();
     bearer_event_mock_Init();
-    long_timer_mock_Init();
+    timer_scheduler_mock_Init();
     scanner_mock_Init();
     event_mock_Init();
     nrf_mesh_externs_mock_Init();
@@ -66,8 +66,8 @@ void tearDown(void)
     transport_mock_Destroy();
     bearer_event_mock_Verify();
     bearer_event_mock_Destroy();
-    long_timer_mock_Verify();
-    long_timer_mock_Destroy();
+    timer_scheduler_mock_Verify();
+    timer_scheduler_mock_Destroy();
     scanner_mock_Verify();
     scanner_mock_Destroy();
     event_mock_Verify();
diff --git a/mesh/test/src/ut_timer.c b/mesh/test/src/ut_timer.c
index 3a3ba3cca..fc9f856cc 100644
--- a/mesh/test/src/ut_timer.c
+++ b/mesh/test/src/ut_timer.c
@@ -48,12 +48,12 @@
 #include "nrf_error.h"
 
 #define TIMER_US_TO_TICKS(US)                              \
-            ((uint32_t)ROUNDED_DIV(                        \
+            (ROUNDED_DIV(                                  \
             (US) * (uint64_t)APP_TIMER_CLOCK_FREQ,         \
             1000000 * (APP_TIMER_CONFIG_RTC_FREQUENCY + 1)))
 
 #define TIMER_TICKS_TO_US(TICKS)                           \
-            ((uint32_t)ROUNDED_DIV(                        \
+            (ROUNDED_DIV(                                  \
             (TICKS) * 1000000ull * (APP_TIMER_CONFIG_RTC_FREQUENCY + 1),         \
             APP_TIMER_CLOCK_FREQ))
 
@@ -63,6 +63,10 @@
 #define OVFW_TIMESTAMP        512000000ul
 #define OVFW_TICKS            0x1000000ul
 
+/* Long timeout test defines. */
+#define LONG_TIMEOUT_TICKS    ((uint64_t)UINT32_MAX * 2 + 2)
+#define LONG_START_TIME_US    1ul
+
 extern void nrf_mesh_timer_tail_handle(void);
 extern void nrf_mesh_timer_ovfw_handle(void);
 
@@ -75,7 +79,7 @@ static bool m_is_timer_init;
 // function does not handle more then 1 overflow
 static void timer_now_smart_mock(timestamp_t timestamp)
 {
-    uint32_t tikcs = TIMER_US_TO_TICKS(timestamp);
+    uint64_t tikcs = TIMER_US_TO_TICKS(timestamp);
 
     NRF_RTC1->EVENTS_OVRFLW = tikcs >> RTC_RESOLUTION ? 1 : 0;
     NRF_RTC1->COUNTER = tikcs & APP_TIMER_MAX_CNT_VAL;
@@ -99,6 +103,16 @@ static void timer_ovfw_cb(timestamp_t timestamp)
     TEST_ASSERT_EQUAL(TIMER_TICKS_TO_US(OVFW_TICKS), timestamp);
 }
 
+static void timer_long_cb(timestamp_t timestamp)
+{
+    TEST_ASSERT_FALSE(m_is_timer_fired);
+    m_is_timer_fired = true;
+    TEST_ASSERT_EQUAL(TIMER_TICKS_TO_US(LONG_TIMEOUT_TICKS + LONG_START_TIME_US), timestamp);
+    TEST_ASSERT_EQUAL(TIMER_TICKS_TO_US(LONG_TIMEOUT_TICKS + LONG_START_TIME_US), timer_now());
+    TEST_ASSERT_TRUE(timestamp > UINT32_MAX);
+    TEST_ASSERT_TRUE(timestamp < UINT64_MAX / 2);
+}
+
 bool is_app_timer_init(void)
 {
     bool retuned_value = m_is_timer_init;
@@ -140,6 +154,7 @@ void test_timer_now(void)
 {
     timestamp_t expected1;
     timestamp_t expected2;
+    timestamp_t expected3;
 
     // normal case
     NRF_RTC1->EVENTS_OVRFLW = 0;
@@ -157,6 +172,21 @@ void test_timer_now(void)
 
     TEST_ASSERT_EQUAL((timestamp_t)TIMER_TICKS_TO_US((1ul << 24) | 0), expected2);
     TEST_ASSERT_TRUE(expected1 < expected2);
+
+    // rtc ovfw counter exceeds UINT32_MAX, timer_now() exceeds UINT32_MAX
+    timer_now_smart_mock(0);
+    for (uint32_t i = 0; i < 256; i++)
+    {
+        nrf_mesh_timer_ovfw_handle();
+    }
+
+    NRF_RTC1->COUNTER = 1ul;
+
+    expected3 = timer_now();
+
+    TEST_ASSERT_EQUAL((timestamp_t)TIMER_TICKS_TO_US((256ull << 24) | 1), expected3);
+    TEST_ASSERT_TRUE(UINT32_MAX < expected3);
+    TEST_ASSERT_TRUE(expected2 < expected3);
 }
 
 void test_timer_start(void)
@@ -273,3 +303,32 @@ void test_timer_start(void)
     }
     TEST_ASSERT_FALSE(m_is_timer_fired);
 }
+
+/* Check TIMER_TICKS_TO_US/_US_TO_TICKS macros by setting difference between timestamp and
+ * timer_now() more than UINT32_MAX in ticks. */
+void test_long_timeout(void)
+{
+    uint64_t ticks = LONG_TIMEOUT_TICKS;
+    timestamp_t timestamp = TIMER_TICKS_TO_US(ticks);
+
+    TEST_ASSERT_TRUE(timestamp > UINT32_MAX);
+    TEST_ASSERT_TRUE(timestamp < (UINT64_MAX >> 1));
+
+    m_is_timer_fired = false;
+    timer_stop();
+    memset(NRF_RTC1, 0, sizeof(NRF_RTC_Type));
+
+    timer_now_smart_mock(LONG_START_TIME_US);
+    timer_start(timestamp, timer_long_cb);
+
+    for (uint32_t i = 0; i < (ticks >> RTC_RESOLUTION); i++)
+    {
+        nrf_mesh_timer_ovfw_handle();
+    }
+
+    TEST_ASSERT_FALSE(m_is_timer_fired);
+    NRF_RTC1->COUNTER = (LONG_TIMEOUT_TICKS + LONG_START_TIME_US) & APP_TIMER_MAX_CNT_VAL;
+    nrf_mesh_timer_tail_handle();
+
+    TEST_ASSERT_TRUE(m_is_timer_fired);
+}
diff --git a/mesh/test/src/ut_timer_scheduler.c b/mesh/test/src/ut_timer_scheduler.c
index 07ee36612..2f9579706 100644
--- a/mesh/test/src/ut_timer_scheduler.c
+++ b/mesh/test/src/ut_timer_scheduler.c
@@ -118,6 +118,14 @@ static void timer_callback_call_schedule(timestamp_t timestamp, void * p_context
     timer_sch_schedule((timer_event_t *) p_context);
 }
 
+static void timer_callback_call_reschedule_far_in_future(timestamp_t timestamp, void * p_context)
+{
+    TEST_ASSERT_NOT_NULL(p_context);
+    timestamp_t next_timestamp = timestamp + UINT32_MAX / 2;
+    ((timer_event_t *) p_context)->cb = timer_sch_cb;
+    timer_sch_reschedule((timer_event_t *) p_context, next_timestamp);
+}
+
 static bool event_is_in_loop(timer_event_t * p_evt)
 {
     for (uint32_t i = 0; i < 1000; i++)
@@ -899,3 +907,71 @@ void test_timer_sch_stop(void)
     TEST_ASSERT_EQUAL(0, m_cb_count);
     TEST_ASSERT_EQUAL(2, m_timer_stop_count);
 }
+
+void test_event_in_future(void)
+{
+    /* Test special case when events that should be scheduled far in future (see nrf_mesh_dfu.c:290,
+     * tx_timeout callback) aren't scheduled in past. */
+
+    m_async_exec = true;
+    timer_event_t evts[3];
+    for (uint32_t i = 0; i < 3; i++)
+    {
+        evts[i].cb = timer_sch_cb;
+        evts[i].timestamp = (i + 1) * 1000;
+        evts[i].interval = 0;
+        evts[i].state = TIMER_EVENT_STATE_UNUSED;
+        evts[i].p_context = &evts[i];
+        TEST_ASSERT_FALSE(timer_sch_is_scheduled(&evts[i]));
+    }
+
+    /* Make the timer schedule an other event from its callback */
+    evts[1].cb = timer_callback_call_reschedule_far_in_future;
+    for (uint32_t i = 0; i < 3; i++)
+    {
+        timer_sch_schedule(&evts[i]);
+        TEST_ASSERT_EQUAL(TIMER_EVENT_STATE_ADDED, evts[i].state);
+        TEST_ASSERT_TRUE(timer_sch_is_scheduled(&evts[i]));
+    }
+    exec_async();
+    for (uint32_t i = 0; i < 3; i++)
+    {
+        TEST_ASSERT_EQUAL(TIMER_EVENT_STATE_ADDED, evts[i].state);
+        TEST_ASSERT_TRUE(timer_sch_is_scheduled(&evts[i]));
+    }
+
+    m_cb_count = 0;
+
+    /* the first timer will fire normally */
+    m_time_now = 1000;
+    m_timer_cb(m_time_now);
+    exec_async();
+    TEST_ASSERT_EQUAL(1, m_cb_count);
+
+    /* The second event will reschedule itself in future. */
+    m_time_now = 2000;
+    m_timer_cb(m_time_now);
+    exec_async();
+    TEST_ASSERT_EQUAL(1, m_cb_count);
+    TEST_ASSERT_EQUAL(TIMER_EVENT_STATE_ADDED, evts[1].state); /* still queued. */
+
+    /* Check that event that should be scheduled far in future isn't scheduled in past. */
+    m_time_now = 2500;
+    m_timer_cb(m_time_now);
+    exec_async();
+    TEST_ASSERT_EQUAL(1, m_cb_count); /* still the same. */
+    TEST_ASSERT_EQUAL(TIMER_EVENT_STATE_ADDED, evts[1].state); /* still queued. */
+
+    /* 3rd event should be scheduled. */
+    m_time_now = 3000;
+    m_timer_cb(m_time_now);
+    exec_async();
+    TEST_ASSERT_EQUAL(2, m_cb_count);
+    TEST_ASSERT_EQUAL(TIMER_EVENT_STATE_ADDED, evts[1].state); /* still queued. */
+
+    m_time_now = 2000 + UINT32_MAX / 2;
+    m_timer_cb(m_time_now);
+    exec_async();
+    TEST_ASSERT_EQUAL(3, m_cb_count);
+    TEST_ASSERT_EQUAL(TIMER_EVENT_STATE_UNUSED, evts[1].state); /* still queued. */
+}
