diff --git a/include/libcamera/timer.h b/include/libcamera/timer.h
index f082339b1fed..853808e07da8 100644
--- a/include/libcamera/timer.h
+++ b/include/libcamera/timer.h
@@ -9,11 +9,14 @@
 
 #include <cstdint>
 
+#include <libcamera/object.h>
 #include <libcamera/signal.h>
 
 namespace libcamera {
 
-class Timer
+class Message;
+
+class Timer : public Object
 {
 public:
 	Timer();
@@ -28,7 +31,13 @@ public:
 
 	Signal<Timer *> timeout;
 
+protected:
+	void message(Message *msg) override;
+
 private:
+	void registerTimer();
+	void unregisterTimer();
+
 	unsigned int interval_;
 	uint64_t deadline_;
 };
diff --git a/src/libcamera/timer.cpp b/src/libcamera/timer.cpp
index 0dcb4e767be3..21c0a444cdce 100644
--- a/src/libcamera/timer.cpp
+++ b/src/libcamera/timer.cpp
@@ -13,6 +13,8 @@
 #include <libcamera/event_dispatcher.h>
 
 #include "log.h"
+#include "message.h"
+#include "thread.h"
 
 /**
  * \file timer.h
@@ -66,7 +68,7 @@ void Timer::start(unsigned int msec)
 		<< "Starting timer " << this << " with interval "
 		<< msec << ": deadline " << deadline_;
 
-	CameraManager::instance()->eventDispatcher()->registerTimer(this);
+	registerTimer();
 }
 
 /**
@@ -79,11 +81,21 @@ void Timer::start(unsigned int msec)
  */
 void Timer::stop()
 {
-	CameraManager::instance()->eventDispatcher()->unregisterTimer(this);
+	unregisterTimer();
 
 	deadline_ = 0;
 }
 
+void Timer::registerTimer()
+{
+	thread()->eventDispatcher()->registerTimer(this);
+}
+
+void Timer::unregisterTimer()
+{
+	thread()->eventDispatcher()->unregisterTimer(this);
+}
+
 /**
  * \brief Check if the timer is running
  * \return True if the timer is running, false otherwise
@@ -112,4 +124,16 @@ bool Timer::isRunning() const
  * The timer pointer is passed as a parameter.
  */
 
+void Timer::message(Message *msg)
+{
+	if (msg->type() == Message::ThreadMoveMessage) {
+		if (deadline_) {
+			unregisterTimer();
+			invokeMethod(this, &Timer::registerTimer);
+		}
+	}
+
+	Object::message(msg);
+}
+
 } /* namespace libcamera */
