diff --git a/src/platform/ESP32/ConfigurationManagerImpl.cpp b/src/platform/ESP32/ConfigurationManagerImpl.cpp
index d138644d4aab8b..8fb56c7427f496 100644
--- a/src/platform/ESP32/ConfigurationManagerImpl.cpp
+++ b/src/platform/ESP32/ConfigurationManagerImpl.cpp
@@ -30,6 +30,7 @@
 #include <platform/ConfigurationManager.h>
 #include <platform/ESP32/ESP32Config.h>
 #include <platform/ESP32/ESP32Utils.h>
+#include <platform/ESP32/ScopedNvsHandle.h>
 #include <platform/internal/GenericConfigurationManagerImpl.ipp>
 
 #if CHIP_DEVICE_CONFIG_ENABLE_ETHERNET
@@ -55,14 +56,9 @@ uint32_t ConfigurationManagerImpl::mTotalOperationalHours = 0;
 
 void ConfigurationManagerImpl::TotalOperationalHoursTimerCallback(TimerHandle_t timer)
 {
-    mTotalOperationalHours++;
-
-    CHIP_ERROR err = ConfigurationMgrImpl().StoreTotalOperationalHours(mTotalOperationalHours);
-
-    if (err != CHIP_NO_ERROR)
-    {
-        ChipLogError(DeviceLayer, "Failed to store total operational hours: %" CHIP_ERROR_FORMAT, err.Format());
-    }
+    // This function is called from the FreeRTOS timer task. Since the task stack is limited,
+    // we avoid logging error messages here to prevent stack overflows.
+    (void) ConfigurationMgrImpl().StoreTotalOperationalHours(++mTotalOperationalHours);
 }
 
 CHIP_ERROR ConfigurationManagerImpl::Init()
@@ -180,6 +176,9 @@ CHIP_ERROR ConfigurationManagerImpl::Init()
     }
 
     {
+        // The total-operational-hours is critical information. It intentionally uses the FreeRTOS timer
+        // to increment the value, this ensures it is not affected by PostEvent failures.
+
         // Start a timer which reloads every one hour and bumps the total operational hours
         TickType_t reloadPeriod   = (1000 * 60 * 60) / portTICK_PERIOD_MS;
         TimerHandle_t timerHandle = xTimerCreate("tOpHrs", reloadPeriod, pdPASS, nullptr, TotalOperationalHoursTimerCallback);
@@ -224,7 +223,13 @@ CHIP_ERROR ConfigurationManagerImpl::GetTotalOperationalHours(uint32_t & totalOp
 
 CHIP_ERROR ConfigurationManagerImpl::StoreTotalOperationalHours(uint32_t totalOperationalHours)
 {
-    return WriteConfigValue(ESP32Config::kCounterKey_TotalOperationalHours, totalOperationalHours);
+    ScopedNvsHandle handle;
+    ESP32Config::Key key = ESP32Config::kCounterKey_TotalOperationalHours;
+
+    ReturnErrorOnFailure(handle.Open(key.Namespace, NVS_READWRITE, ESP32Config::GetPartitionLabelByNamespace(key.Namespace)));
+    ReturnMappedErrorOnFailure(nvs_set_u32(handle, key.Name, totalOperationalHours));
+    ReturnMappedErrorOnFailure(nvs_commit(handle));
+    return CHIP_NO_ERROR;
 }
 
 CHIP_ERROR ConfigurationManagerImpl::GetSoftwareVersionString(char * buf, size_t bufSize)
diff --git a/src/platform/ESP32/ESP32Config.h b/src/platform/ESP32/ESP32Config.h
index 5804f53105c20c..d2056063f0a383 100644
--- a/src/platform/ESP32/ESP32Config.h
+++ b/src/platform/ESP32/ESP32Config.h
@@ -128,7 +128,6 @@ class ESP32Config
 
     static void RunConfigUnitTest(void);
 
-private:
     static const char * GetPartitionLabelByNamespace(const char * ns);
 };