[instance] define ot::Instance class (#2307)

This commit makes the following changes: It defines the public
`otInstance` as an empty opaque structure which is used by all public
C OpenThread APIs. It defines a new class `ot::Instance` (inheriting
from `otInstance) which is then used in core source files. The
functionality related to the instance is also moved/added into the
newly added `Instance` class (as class/static or member methods).
diff --git a/etc/visual-studio/libopenthread-cli-windows.vcxproj b/etc/visual-studio/libopenthread-cli-windows.vcxproj
index 76859c9..047e6f8 100644
--- a/etc/visual-studio/libopenthread-cli-windows.vcxproj
+++ b/etc/visual-studio/libopenthread-cli-windows.vcxproj
@@ -49,6 +49,8 @@
         ..\..\include;
         ..\..\src;
         ..\..\src\core;
+        ..\..\third_party\mbedtls;
+        ..\..\third_party\mbedtls\repo.patched\include;
       </AdditionalIncludeDirectories>
       <WarningLevel>Level3</WarningLevel>
       <SDLCheck>true</SDLCheck>
diff --git a/etc/visual-studio/libopenthread.vcxproj b/etc/visual-studio/libopenthread.vcxproj
index 2f92ae1..eb0f75e 100644
--- a/etc/visual-studio/libopenthread.vcxproj
+++ b/etc/visual-studio/libopenthread.vcxproj
@@ -77,6 +77,7 @@
     <ClCompile Include="..\..\src\core\coap\coap_header.cpp" />
     <ClCompile Include="..\..\src\core\coap\coap_secure.cpp" />
     <ClCompile Include="..\..\src\core\common\crc16.cpp" />
+    <ClCompile Include="..\..\src\core\common\instance.cpp" />
     <ClCompile Include="..\..\src\core\common\locator.cpp" />
     <ClCompile Include="..\..\src\core\common\logging.cpp" />
     <ClCompile Include="..\..\src\core\common\message.cpp" />
@@ -155,6 +156,7 @@
     <ClInclude Include="..\..\src\core\common\context.hpp" />
     <ClInclude Include="..\..\src\core\common\debug.hpp" />
     <ClInclude Include="..\..\src\core\common\encoding.hpp" />
+    <ClInclude Include="..\..\src\core\common\instance.hpp" />
     <ClInclude Include="..\..\src\core\common\locator.hpp" />
     <ClInclude Include="..\..\src\core\common\logging.hpp" />
     <ClInclude Include="..\..\src\core\common\message.hpp" />
diff --git a/etc/visual-studio/libopenthread.vcxproj.filters b/etc/visual-studio/libopenthread.vcxproj.filters
index 2f64f57..1b6526c 100644
--- a/etc/visual-studio/libopenthread.vcxproj.filters
+++ b/etc/visual-studio/libopenthread.vcxproj.filters
@@ -129,6 +129,9 @@
     <ClCompile Include="..\..\src\core\coap\coap_secure.cpp">
       <Filter>Source Files\coap</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\common\instance.cpp">
+      <Filter>Source Files\common</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\common\locator.cpp">
       <Filter>Source Files\common</Filter>
     </ClCompile>
@@ -353,6 +356,9 @@
     <ClInclude Include="..\..\src\core\common\encoding.hpp">
       <Filter>Header Files\common</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\common\instance.hpp">
+      <Filter>Header Files\common</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\common\locator.hpp">
       <Filter>Header Files\common</Filter>
     </ClInclude>
diff --git a/etc/visual-studio/libopenthread_k.vcxproj b/etc/visual-studio/libopenthread_k.vcxproj
index 66af508..f687a92 100644
--- a/etc/visual-studio/libopenthread_k.vcxproj
+++ b/etc/visual-studio/libopenthread_k.vcxproj
@@ -86,6 +86,7 @@
     <ClCompile Include="..\..\src\core\coap\coap_header.cpp" />
     <ClCompile Include="..\..\src\core\coap\coap_secure.cpp" />
     <ClCompile Include="..\..\src\core\common\crc16.cpp" />
+    <ClCompile Include="..\..\src\core\common\instance.cpp" />
     <ClCompile Include="..\..\src\core\common\locator.cpp" />
     <ClCompile Include="..\..\src\core\common\logging.cpp" />
     <ClCompile Include="..\..\src\core\common\message.cpp" />
@@ -187,6 +188,7 @@
     <ClInclude Include="..\..\src\core\common\crc16.hpp" />
     <ClInclude Include="..\..\src\core\common\debug.hpp" />
     <ClInclude Include="..\..\src\core\common\encoding.hpp" />
+    <ClInclude Include="..\..\src\core\common\instance.hpp" />
     <ClInclude Include="..\..\src\core\common\locator.hpp" />
     <ClInclude Include="..\..\src\core\common\logging.hpp" />
     <ClInclude Include="..\..\src\core\common\message.hpp" />
@@ -232,7 +234,6 @@
     <ClInclude Include="..\..\src\core\net\udp6.hpp" />
     <ClInclude Include="..\..\src\core\openthread-core-config.h" />
     <ClInclude Include="..\..\src\core\openthread-core-default-config.h" />
-    <ClInclude Include="..\..\src\core\openthread-instance.h" />
     <ClInclude Include="..\..\src\core\thread\address_resolver.hpp" />
     <ClInclude Include="..\..\src\core\meshcop\announce_begin_server.hpp" />
     <ClInclude Include="..\..\src\core\thread\data_poll_manager.hpp" />
diff --git a/etc/visual-studio/libopenthread_k.vcxproj.filters b/etc/visual-studio/libopenthread_k.vcxproj.filters
index 536e40f..816a4bf 100644
--- a/etc/visual-studio/libopenthread_k.vcxproj.filters
+++ b/etc/visual-studio/libopenthread_k.vcxproj.filters
@@ -129,6 +129,9 @@
     <ClCompile Include="..\..\src\core\coap\coap_secure.cpp">
       <Filter>Source Files\coap</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\common\instance.cpp">
+      <Filter>Source Files\common</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\common\locator.cpp">
       <Filter>Source Files\common</Filter>
     </ClCompile>
@@ -353,6 +356,9 @@
     <ClInclude Include="..\..\src\core\common\encoding.hpp">
       <Filter>Header Files\common</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\common\instance.hpp">
+      <Filter>Header Files\common</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\common\locator.hpp">
       <Filter>Header Files\common</Filter>
     </ClInclude>
@@ -569,9 +575,6 @@
     <ClInclude Include="..\..\src\core\openthread-core-default-config.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\openthread-instance.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\include\openthread\types.h">
       <Filter>Header Files\openthread</Filter>
     </ClInclude>
diff --git a/examples/platforms/emsk/platform-emsk.h b/examples/platforms/emsk/platform-emsk.h
index 038f72e..c0f2d1f 100755
--- a/examples/platforms/emsk/platform-emsk.h
+++ b/examples/platforms/emsk/platform-emsk.h
@@ -43,9 +43,6 @@
 
 #include "board/board.h"
 
-// Global OpenThread instance structure
-extern otInstance *sInstance;
-
 /**
  * This function initializes the alarm service used by OpenThread.
  *
diff --git a/examples/platforms/emsk/platform.c b/examples/platforms/emsk/platform.c
index ac79e40..acc73fc 100755
--- a/examples/platforms/emsk/platform.c
+++ b/examples/platforms/emsk/platform.c
@@ -55,8 +55,6 @@
 
 void PlatformProcessDrivers(otInstance *aInstance)
 {
-    // sInstance = aInstance;
-
     emskUartProcess();
     emskRadioProcess(aInstance);
     emskAlarmProcess(aInstance);
diff --git a/examples/platforms/emsk/random.c b/examples/platforms/emsk/random.c
index e609166..c7ffdd7 100755
--- a/examples/platforms/emsk/random.c
+++ b/examples/platforms/emsk/random.c
@@ -68,15 +68,24 @@
 {
     otError error = OT_ERROR_NONE;
     uint8_t channel = 0;
+    otInstance *aInstance = NULL;
 
     otEXPECT_ACTION(aOutput && aOutputLength, error = OT_ERROR_INVALID_ARGS);
 
+    // TODO: `otPlatRandomGet()` and `otPlatRandomGetTrue()` should include a pointer to the
+    // owning OpenThread Instance as an input argument (similar to other platform APIs).
+    //
+    // The platform implementation requires to know the OpenThread instance to be able to
+    // use other radio platform APIs. However, the emsk platform implementation of radio API
+    // does not actually use the passed-in instance argument. Till the above TODO is done, as
+    // a workaround, a NULL `aInstance` is used instead.
+
     /* disable radio*/
-    if (otPlatRadioIsEnabled(sInstance))
+    if (otPlatRadioIsEnabled(aInstance))
     {
         channel = (mrf24j40_read_long_ctrl_reg(MRF24J40_RFCON0) >> 4) + 11;
-        otPlatRadioSleep(sInstance);
-        otPlatRadioDisable(sInstance);
+        otPlatRadioSleep(aInstance);
+        otPlatRadioDisable(aInstance);
     }
 
     /*
@@ -97,8 +106,8 @@
     if (channel)
     {
         emskRadioInit();
-        otPlatRadioEnable(sInstance);
-        otPlatRadioReceive(sInstance, channel);
+        otPlatRadioEnable(aInstance);
+        otPlatRadioReceive(aInstance, channel);
     }
 
 exit:
diff --git a/include/openthread/instance.h b/include/openthread/instance.h
index bcb830d..ac9de8f 100644
--- a/include/openthread/instance.h
+++ b/include/openthread/instance.h
@@ -120,7 +120,7 @@
  * @param[in]  aApiInstance  The OpenThread api instance.
  * @param[in]  aDeviceGuid   The device guid to create an OpenThread context for.
  *
- * @retval otInstance*  The new OpenThread device instance structure for the device.
+ * @returns  The new OpenThread device instance structure for the device.
  *
  * @sa otFreeMemory
  *
@@ -132,7 +132,7 @@
  *
  * @param[in] aContext  The OpenThread context structure.
  *
- * @retval GUID  The device GUID.
+ * @returns  The device GUID.
  *
  */
 OTAPI GUID OTCALL otGetDeviceGuid(otInstance *aInstance);
@@ -142,7 +142,7 @@
  *
  * @param[in] aContext  The OpenThread context structure.
  *
- * @retval uint32_t  The device IfIndex.
+ * @returns The device IfIndex.
  *
  */
 OTAPI uint32_t OTCALL otGetDeviceIfIndex(otInstance *aInstance);
@@ -152,7 +152,7 @@
  *
  * @param[in] aContext  The OpenThread context structure.
  *
- * @retval uint32_t  The compartment ID.
+ * @returns  The compartment ID.
  *
  */
 OTAPI uint32_t OTCALL otGetCompartmentId(otInstance *aInstance);
@@ -162,9 +162,8 @@
 /**
  * This function initializes the OpenThread library.
  *
- *
  * This function initializes OpenThread and prepares it for subsequent OpenThread API calls.  This function must be
- * called before any other calls to OpenThread. By default, OpenThread is initialized in the 'enabled' state.
+ * called before any other calls to OpenThread.
  *
  * This function is available and can only be used when support for multiple OpenThread instances is enabled.
  *
@@ -172,9 +171,9 @@
  * @param[inout] aInstanceBufferSize  On input, the size of aInstanceBuffer. On output, if not enough space for
  *                                    otInstance, the number of bytes required for otInstance.
  *
- * @retval otInstance*  The new OpenThread instance structure.
+ * @returns  A pointer to the new OpenThread instance.
  *
- * @sa otContextFinalize
+ * @sa otInstanceFinalize
  *
  */
 otInstance *otInstanceInit(void *aInstanceBuffer, size_t *aInstanceBufferSize);
@@ -183,11 +182,11 @@
  * This function initializes the static single instance of the OpenThread library.
  *
  * This function initializes OpenThread and prepares it for subsequent OpenThread API calls.  This function must be
- * called before any other calls to OpenThread. By default, OpenThread is initialized in the 'enabled' state.
+ * called before any other calls to OpenThread.
  *
  * This function is available and can only be used when support for multiple OpenThread instances is disabled.
  *
- * @retval A pointer to the single OpenThread instance structure.
+ * @returns A pointer to the single OpenThread instance.
  *
  */
 otInstance *otInstanceInitSingle(void);
@@ -195,11 +194,9 @@
 /**
  * This function indicates whether or not the instance is valid/initialized.
  *
- * For single-instance case, the instance is considered valid if it is acquired and initialized using
- * `otInstanceInitSingle()`. A subsequent call to `otInstanceFinalize()` causes the instance to be considered as
- * invalid (not initialized).
- *
- * For multi-instance case, any non-NULL instance pointer is considered as valid/initialized.
+ * The instance is considered valid if it is acquired and initialized using either `otInstanceInitSingle()` (in single
+ * instance case) or `otInstanceInit()` (in multi instance case). A subsequent call to `otInstanceFinalize()` causes
+ * the instance to be considered as uninitialized.
  *
  * @param[in] aInstance A pointer to an OpenThread instance.
  *
diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am
index 80b36eb..ee2136b 100644
--- a/src/cli/Makefile.am
+++ b/src/cli/Makefile.am
@@ -31,14 +31,14 @@
 #----------------------------------------
 #
 # This library on the face of it, appears to be identical
-# for both the MTD and FTD varients, however ...
+# for both the MTD and FTD variants, however ...
 #
 # The source code here includes numerous OpenThread internal headers.
 # Due to the "domino-effect" other internal headers are included.
 #
 # For example:
-#     cli.cpp includes: 
-#            src/core/openthread-instance.h
+#     cli.cpp includes:
+#            src/core/common/instance.hpp
 # Which Includes:
 #            src/core/therad/thread_netif.hpp
 # Which Includes:
@@ -51,8 +51,8 @@
 # The FTD flavor has many private components (class variables).
 # The MTD flavor has no private components.
 #
-# Bottom line: The Class(structs) are thus different in the downstream 
-# libs. At this level (in the CLI, and likewise in the NCP) they are 
+# Bottom line: The Class(structs) are thus different in the downstream
+# libs. At this level (in the CLI, and likewise in the NCP) they are
 # functionally identical.
 #
 # ORIGINALLY (historical note about how things are/where built):
diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp
index 69f5f8a..2e60275 100644
--- a/src/cli/cli.cpp
+++ b/src/cli/cli.cpp
@@ -66,7 +66,6 @@
 #include <openthread/icmp6.h>
 #include <openthread/platform/uart.h>
 
-#include "openthread-instance.h"
 #include "common/new.hpp"
 #include "net/ip6.hpp"
 #endif
@@ -252,7 +251,7 @@
 typedef otPtr<const uint8_t> otBufferPtr;
 typedef otPtr<const char> otStringPtr;
 
-Interpreter::Interpreter(otInstance *aInstance):
+Interpreter::Interpreter(Instance *aInstance):
 #if OPENTHREAD_ENABLE_APPLICATION_COAP
     mCoap(*this),
 #endif
diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp
index af38238..ad300de 100644
--- a/src/cli/cli.hpp
+++ b/src/cli/cli.hpp
@@ -53,6 +53,7 @@
 
 #include "common/code_utils.hpp"
 #include "common/context.hpp"
+#include "common/instance.hpp"
 
 #ifndef OTDLL
 #include <openthread/dhcp6_client.h>
@@ -104,7 +105,7 @@
      *
      * @param[in]  aInstance  The OpenThread instance structure.
      */
-    Interpreter(otInstance *aInstance);
+    Interpreter(Instance *aInstance);
 
     /**
      * This method interprets a CLI command.
@@ -396,7 +397,7 @@
     struct otCliContext
     {
         Interpreter *mInterpreter;
-        otInstance  *mInstance;
+        Instance    *mInstance;
     };
     otCliContext mInstances[MAX_CLI_OT_INSTANCES];
     uint8_t mInstancesLength;
@@ -426,7 +427,7 @@
 
 #endif
 
-    otInstance *mInstance;
+    Instance *mInstance;
 };
 
 }  // namespace Cli
diff --git a/src/cli/cli_console.cpp b/src/cli/cli_console.cpp
index c2f208b..126f9f7 100644
--- a/src/cli/cli_console.cpp
+++ b/src/cli/cli_console.cpp
@@ -39,6 +39,7 @@
 #include "utils/wrap_string.h"
 
 #include "cli/cli.hpp"
+#include "common/instance.hpp"
 #include "common/new.hpp"
 
 namespace ot {
@@ -50,7 +51,9 @@
 
 extern "C" void otCliConsoleInit(otInstance *aInstance, otCliConsoleOutputCallback aCallback, void *aContext)
 {
-    sServer = new(&sCliConsoleRaw) Console(aInstance);
+    Instance *instance = static_cast<Instance *>(aInstance);
+
+    sServer = new(&sCliConsoleRaw) Console(instance);
     sServer->SetOutputCallback(aCallback);
     sServer->SetContext(aContext);
 }
@@ -60,7 +63,7 @@
     sServer->ReceiveTask(aBuf, aBufLength);
 }
 
-Console::Console(otInstance *aInstance):
+Console::Console(Instance *aInstance):
     mCallback(NULL),
     mContext(NULL),
     mInterpreter(aInstance)
diff --git a/src/cli/cli_console.hpp b/src/cli/cli_console.hpp
index 5b81e6e..51808ed 100644
--- a/src/cli/cli_console.hpp
+++ b/src/cli/cli_console.hpp
@@ -57,7 +57,7 @@
      * @param[in]  aInstance  The OpenThread instance structure.
      *
      */
-    Console(otInstance *aInstance);
+    Console(Instance *aInstance);
 
     /**
      * This method delivers raw characters to the client.
diff --git a/src/cli/cli_instance.cpp b/src/cli/cli_instance.cpp
index 8116238..23b0373 100644
--- a/src/cli/cli_instance.cpp
+++ b/src/cli/cli_instance.cpp
@@ -61,7 +61,7 @@
         for (uint8_t i = 0; i < mInstancesLength; i++)
         {
             mInstances[i].mInterpreter = this;
-            mInstances[i].mInstance = otInstanceInit(mApiInstance, &aDeviceList->aDevices[i]);
+            mInstances[i].mInstance = static_cast<Instance *>(otInstanceInit(mApiInstance, &aDeviceList->aDevices[i]));
             assert(mInstances[i].mInstance);
             otSetStateChangedCallback(mInstances[i].mInstance, &Interpreter::s_HandleNetifStateChanged, &mInstances[i]);
         }
diff --git a/src/cli/cli_uart.cpp b/src/cli/cli_uart.cpp
index a5af595..df51752 100644
--- a/src/cli/cli_uart.cpp
+++ b/src/cli/cli_uart.cpp
@@ -64,7 +64,9 @@
 
 extern "C" void otCliUartInit(otInstance *aInstance)
 {
-    Uart::sUartServer = new(&sCliUartRaw) Uart(aInstance);
+    Instance *instance = static_cast<Instance *>(aInstance);
+
+    Uart::sUartServer = new(&sCliUartRaw) Uart(instance);
 }
 
 extern "C" void otCliUartSetUserCommands(const otCliCommand *aUserCommands, uint8_t aLength)
@@ -90,7 +92,7 @@
     Uart::sUartServer->GetInterpreter().AppendResult(aError);
 }
 
-Uart::Uart(otInstance *aInstance):
+Uart::Uart(Instance *aInstance):
     mInterpreter(aInstance)
 {
     mRxLength = 0;
@@ -193,13 +195,13 @@
      *
      * Yes, while rare it is a race condition that is hard to debug.
      *
-     * Thus this is here to afirmatively LOG exactly when the CLI
+     * Thus this is here to affirmatively LOG exactly when the CLI
      * command is being executed.
      */
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     /* TODO: how exactly do we get the instance here? */
 #else
-    otLogInfoCli(otGetInstance(),  "execute command: %s", mRxBuffer);
+    otLogInfoCli(&Instance::Get(),  "execute command: %s", mRxBuffer);
 #endif
 #endif
     mInterpreter.ProcessLine(mRxBuffer, mRxLength, *this);
diff --git a/src/cli/cli_uart.hpp b/src/cli/cli_uart.hpp
index 3ba1988..c7e06c9 100644
--- a/src/cli/cli_uart.hpp
+++ b/src/cli/cli_uart.hpp
@@ -40,8 +40,10 @@
 
 #include "cli/cli.hpp"
 #include "cli/cli_server.hpp"
+#include "common/instance.hpp"
 #include "common/tasklet.hpp"
 
+
 namespace ot {
 namespace Cli {
 
@@ -58,7 +60,7 @@
      * @param[in]  aInstance  The OpenThread instance structure.
      *
      */
-    Uart(otInstance *aInstance);
+    Uart(Instance *aInstance);
 
     /**
      * This method delivers raw characters to the client.
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index de60614..6618968 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -116,6 +116,7 @@
     coap/coap_header.cpp              \
     coap/coap_secure.cpp              \
     common/crc16.cpp                  \
+    common/instance.cpp               \
     common/logging.cpp                \
     common/locator.cpp                \
     common/message.cpp                \
@@ -200,8 +201,6 @@
 HEADERS_COMMON                      = \
     openthread-core-config.h          \
     openthread-core-default-config.h  \
-    openthread-instance.h             \
-    openthread-single-instance.h      \
     api/link_raw.hpp                  \
     coap/coap.hpp                     \
     coap/coap_header.hpp              \
@@ -211,6 +210,7 @@
     common/crc16.hpp                  \
     common/debug.hpp                  \
     common/encoding.hpp               \
+    common/instance.hpp               \
     common/locator.hpp                \
     common/logging.hpp                \
     common/message.hpp                \
diff --git a/src/core/api/border_router_api.cpp b/src/core/api/border_router_api.cpp
index 5a30227..b1c7da3 100644
--- a/src/core/api/border_router_api.cpp
+++ b/src/core/api/border_router_api.cpp
@@ -37,17 +37,18 @@
 
 #include <openthread/border_router.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
 otError otBorderRouterGetNetData(otInstance *aInstance, bool aStable, uint8_t *aData, uint8_t *aDataLength)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aData != NULL && aDataLength != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetNetworkDataLocal().GetNetworkData(aStable, aData, *aDataLength);
+    error = instance.GetThreadNetif().GetNetworkDataLocal().GetNetworkData(aStable, aData, *aDataLength);
 
 exit:
     return error;
@@ -56,6 +57,7 @@
 otError otBorderRouterAddOnMeshPrefix(otInstance *aInstance, const otBorderRouterConfig *aConfig)
 {
     uint8_t flags = 0;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     if (aConfig->mPreferred)
     {
@@ -87,24 +89,28 @@
         flags |= NetworkData::BorderRouterEntry::kOnMeshFlag;
     }
 
-    return aInstance->mThreadNetif.GetNetworkDataLocal().AddOnMeshPrefix(aConfig->mPrefix.mPrefix.mFields.m8,
-                                                                         aConfig->mPrefix.mLength,
-                                                                         aConfig->mPreference, flags, aConfig->mStable);
+    return instance.GetThreadNetif().GetNetworkDataLocal().AddOnMeshPrefix(aConfig->mPrefix.mPrefix.mFields.m8,
+                                                                           aConfig->mPrefix.mLength,
+                                                                           aConfig->mPreference, flags, aConfig->mStable);
 }
 
 otError otBorderRouterRemoveOnMeshPrefix(otInstance *aInstance, const otIp6Prefix *aPrefix)
 {
-    return aInstance->mThreadNetif.GetNetworkDataLocal().RemoveOnMeshPrefix(aPrefix->mPrefix.mFields.m8, aPrefix->mLength);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetNetworkDataLocal().RemoveOnMeshPrefix(aPrefix->mPrefix.mFields.m8,
+                                                                              aPrefix->mLength);
 }
 
 otError otBorderRouterGetNextOnMeshPrefix(otInstance *aInstance, otNetworkDataIterator *aIterator,
                                           otBorderRouterConfig *aConfig)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aIterator && aConfig, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetNetworkDataLocal().GetNextOnMeshPrefix(aIterator, aConfig);
+    error = instance.GetThreadNetif().GetNetworkDataLocal().GetNextOnMeshPrefix(aIterator, aConfig);
 
 exit:
     return error;
@@ -112,25 +118,30 @@
 
 otError otBorderRouterAddRoute(otInstance *aInstance, const otExternalRouteConfig *aConfig)
 {
-    return aInstance->mThreadNetif.GetNetworkDataLocal().AddHasRoutePrefix(aConfig->mPrefix.mPrefix.mFields.m8,
-                                                                           aConfig->mPrefix.mLength,
-                                                                           aConfig->mPreference, aConfig->mStable);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetNetworkDataLocal().AddHasRoutePrefix(aConfig->mPrefix.mPrefix.mFields.m8,
+                                                                             aConfig->mPrefix.mLength,
+                                                                             aConfig->mPreference, aConfig->mStable);
 }
 
 otError otBorderRouterRemoveRoute(otInstance *aInstance, const otIp6Prefix *aPrefix)
 {
-    return aInstance->mThreadNetif.GetNetworkDataLocal().RemoveHasRoutePrefix(aPrefix->mPrefix.mFields.m8,
-                                                                              aPrefix->mLength);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetNetworkDataLocal().RemoveHasRoutePrefix(aPrefix->mPrefix.mFields.m8,
+                                                                                aPrefix->mLength);
 }
 
 otError otBorderRouterGetNextRoute(otInstance *aInstance, otNetworkDataIterator *aIterator,
                                    otExternalRouteConfig *aConfig)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aIterator && aConfig, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetNetworkDataLocal().GetNextExternalRoute(aIterator, aConfig);
+    error = instance.GetThreadNetif().GetNetworkDataLocal().GetNextExternalRoute(aIterator, aConfig);
 
 exit:
     return error;
@@ -138,7 +149,9 @@
 
 otError otBorderRouterRegister(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetNetworkDataLocal().SendServerDataNotification();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetNetworkDataLocal().SendServerDataNotification();
 }
 
 #endif  // OPENTHREAD_ENABLE_BORDER_ROUTER
diff --git a/src/core/api/child_supervision_api.cpp b/src/core/api/child_supervision_api.cpp
index c7733be..f667f53 100644
--- a/src/core/api/child_supervision_api.cpp
+++ b/src/core/api/child_supervision_api.cpp
@@ -34,7 +34,7 @@
 #include "openthread-core-config.h"
 #include "openthread/child_supervision.h"
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
@@ -42,22 +42,30 @@
 
 uint16_t otChildSupervisionGetInterval(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetChildSupervisor().GetSupervisionInterval();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetChildSupervisor().GetSupervisionInterval();
 }
 
 void otChildSupervisionSetInterval(otInstance *aInstance, uint16_t aInterval)
 {
-    aInstance->mThreadNetif.GetChildSupervisor().SetSupervisionInterval(aInterval);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetChildSupervisor().SetSupervisionInterval(aInterval);
 }
 
 uint16_t otChildSupervisionGetCheckTimeout(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetSupervisionListener().GetTimeout();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetSupervisionListener().GetTimeout();
 }
 
 void otChildSupervisionSetCheckTimeout(otInstance *aInstance, uint16_t aTimeout)
 {
-    aInstance->mThreadNetif.GetSupervisionListener().SetTimeout(aTimeout);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetSupervisionListener().SetTimeout(aTimeout);
 }
 
 #endif  // OPENTHREAD_ENABLE_CHILD_SUPERVISION
diff --git a/src/core/api/coap_api.cpp b/src/core/api/coap_api.cpp
index ed0585b..4b6209a 100644
--- a/src/core/api/coap_api.cpp
+++ b/src/core/api/coap_api.cpp
@@ -35,7 +35,7 @@
 
 #include <openthread/coap.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 #include "coap/coap_header.hpp"
 
 #if OPENTHREAD_ENABLE_APPLICATION_COAP
@@ -141,8 +141,10 @@
 otMessage *otCoapNewMessage(otInstance *aInstance, const otCoapHeader *aHeader)
 {
     Message *message;
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
     VerifyOrExit(aHeader != NULL, message = NULL);
-    message = aInstance->mApplicationCoap.NewMessage(*(static_cast<const Coap::Header *>(aHeader)));
+    message = instance.GetApplicationCoap().NewMessage(*(static_cast<const Coap::Header *>(aHeader)));
 exit:
     return message;
 }
@@ -150,7 +152,9 @@
 otError otCoapSendRequest(otInstance *aInstance, otMessage *aMessage, const otMessageInfo *aMessageInfo,
                           otCoapResponseHandler aHandler, void *aContext)
 {
-    return aInstance->mApplicationCoap.SendMessage(
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetApplicationCoap().SendMessage(
                *static_cast<Message *>(aMessage),
                *static_cast<const Ip6::MessageInfo *>(aMessageInfo),
                aHandler, aContext);
@@ -158,32 +162,44 @@
 
 otError otCoapStart(otInstance *aInstance, uint16_t aPort)
 {
-    return aInstance->mApplicationCoap.Start(aPort);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetApplicationCoap().Start(aPort);
 }
 
 otError otCoapStop(otInstance *aInstance)
 {
-    return aInstance->mApplicationCoap.Stop();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetApplicationCoap().Stop();
 }
 
 otError otCoapAddResource(otInstance *aInstance, otCoapResource *aResource)
 {
-    return aInstance->mApplicationCoap.AddResource(*static_cast<Coap::Resource *>(aResource));
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetApplicationCoap().AddResource(*static_cast<Coap::Resource *>(aResource));
 }
 
 void otCoapRemoveResource(otInstance *aInstance, otCoapResource *aResource)
 {
-    aInstance->mApplicationCoap.RemoveResource(*static_cast<Coap::Resource *>(aResource));
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetApplicationCoap().RemoveResource(*static_cast<Coap::Resource *>(aResource));
 }
 
 void otCoapSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandler, void *aContext)
 {
-    aInstance->mApplicationCoap.SetDefaultHandler(aHandler, aContext);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetApplicationCoap().SetDefaultHandler(aHandler, aContext);
 }
 
 otError otCoapSendResponse(otInstance *aInstance, otMessage *aMessage, const otMessageInfo *aMessageInfo)
 {
-    return aInstance->mApplicationCoap.SendMessage(
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetApplicationCoap().SendMessage(
                *static_cast<Message *>(aMessage), *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
 }
 
diff --git a/src/core/api/commissioner_api.cpp b/src/core/api/commissioner_api.cpp
index 81df3ae..467a49f 100644
--- a/src/core/api/commissioner_api.cpp
+++ b/src/core/api/commissioner_api.cpp
@@ -35,7 +35,7 @@
 
 #include <openthread/commissioner.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
@@ -44,10 +44,12 @@
     otError error = OT_ERROR_DISABLED_FEATURE;
 
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
-    error = aInstance->mThreadNetif.GetCommissioner().Start();
-#else  // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetCommissioner().Start();
+#else
     OT_UNUSED_VARIABLE(aInstance);
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#endif
 
     return error;
 }
@@ -57,10 +59,12 @@
     otError error = OT_ERROR_DISABLED_FEATURE;
 
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
-    error = aInstance->mThreadNetif.GetCommissioner().Stop();
-#else  // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetCommissioner().Stop();
+#else
     OT_UNUSED_VARIABLE(aInstance);
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#endif
 
     return error;
 }
@@ -70,15 +74,18 @@
 {
     otError error = OT_ERROR_DISABLED_FEATURE;
 
+
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
-    error = aInstance->mThreadNetif.GetCommissioner().AddJoiner(static_cast<const Mac::ExtAddress *>(aEui64), aPSKd,
-                                                                aTimeout);
-#else  // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetCommissioner().AddJoiner(static_cast<const Mac::ExtAddress *>(aEui64), aPSKd,
+                                                                  aTimeout);
+#else
     OT_UNUSED_VARIABLE(aInstance);
     OT_UNUSED_VARIABLE(aEui64);
     OT_UNUSED_VARIABLE(aPSKd);
     OT_UNUSED_VARIABLE(aTimeout);
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#endif
 
     return error;
 }
@@ -88,11 +95,13 @@
     otError error = OT_ERROR_DISABLED_FEATURE;
 
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
-    error = aInstance->mThreadNetif.GetCommissioner().RemoveJoiner(static_cast<const Mac::ExtAddress *>(aEui64), 0);
-#else  // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetCommissioner().RemoveJoiner(static_cast<const Mac::ExtAddress *>(aEui64), 0);
+#else
     OT_UNUSED_VARIABLE(aInstance);
     OT_UNUSED_VARIABLE(aEui64);
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#endif
 
     return error;
 }
@@ -102,11 +111,13 @@
     otError error = OT_ERROR_DISABLED_FEATURE;
 
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
-    error = aInstance->mThreadNetif.GetCommissioner().SetProvisioningUrl(aProvisioningUrl);
-#else  // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetCommissioner().SetProvisioningUrl(aProvisioningUrl);
+#else
     OT_UNUSED_VARIABLE(aInstance);
     OT_UNUSED_VARIABLE(aProvisioningUrl);
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#endif
 
     return error;
 }
@@ -117,15 +128,17 @@
     otError error = OT_ERROR_DISABLED_FEATURE;
 
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
-    error = aInstance->mThreadNetif.GetCommissioner().GetAnnounceBeginClient().SendRequest(
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetCommissioner().GetAnnounceBeginClient().SendRequest(
                 aChannelMask, aCount, aPeriod, *static_cast<const Ip6::Address *>(aAddress));
-#else  // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#else
     OT_UNUSED_VARIABLE(aInstance);
     OT_UNUSED_VARIABLE(aChannelMask);
     OT_UNUSED_VARIABLE(aCount);
     OT_UNUSED_VARIABLE(aPeriod);
     OT_UNUSED_VARIABLE(aAddress);
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#endif
 
     return error;
 }
@@ -137,10 +150,12 @@
     otError error = OT_ERROR_DISABLED_FEATURE;
 
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
-    error = aInstance->mThreadNetif.GetCommissioner().GetEnergyScanClient().SendQuery(
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetCommissioner().GetEnergyScanClient().SendQuery(
                 aChannelMask, aCount, aPeriod, aScanDuration, *static_cast<const Ip6::Address *>(aAddress),
                 aCallback, aContext);
-#else  // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#else
     OT_UNUSED_VARIABLE(aInstance);
     OT_UNUSED_VARIABLE(aChannelMask);
     OT_UNUSED_VARIABLE(aCount);
@@ -149,7 +164,7 @@
     OT_UNUSED_VARIABLE(aAddress);
     OT_UNUSED_VARIABLE(aCallback);
     OT_UNUSED_VARIABLE(aContext);
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#endif
 
     return error;
 }
@@ -161,16 +176,18 @@
     otError error = OT_ERROR_DISABLED_FEATURE;
 
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
-    error = aInstance->mThreadNetif.GetCommissioner().GetPanIdQueryClient().SendQuery(
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetCommissioner().GetPanIdQueryClient().SendQuery(
                 aPanId, aChannelMask, *static_cast<const Ip6::Address *>(aAddress), aCallback, aContext);
-#else  // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#else
     OT_UNUSED_VARIABLE(aInstance);
     OT_UNUSED_VARIABLE(aPanId);
     OT_UNUSED_VARIABLE(aChannelMask);
     OT_UNUSED_VARIABLE(aAddress);
     OT_UNUSED_VARIABLE(aCallback);
     OT_UNUSED_VARIABLE(aContext);
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#endif
 
     return error;
 }
@@ -180,12 +197,14 @@
     otError error = OT_ERROR_DISABLED_FEATURE;
 
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
-    error = aInstance->mThreadNetif.GetCommissioner().SendMgmtCommissionerGetRequest(aTlvs, aLength);
-#else  // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetCommissioner().SendMgmtCommissionerGetRequest(aTlvs, aLength);
+#else
     OT_UNUSED_VARIABLE(aInstance);
     OT_UNUSED_VARIABLE(aTlvs);
     OT_UNUSED_VARIABLE(aLength);
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#endif
 
     return error;
 }
@@ -196,13 +215,15 @@
     otError error = OT_ERROR_DISABLED_FEATURE;
 
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
-    error = aInstance->mThreadNetif.GetCommissioner().SendMgmtCommissionerSetRequest(*aDataset, aTlvs, aLength);
-#else  // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetCommissioner().SendMgmtCommissionerSetRequest(*aDataset, aTlvs, aLength);
+#else
     OT_UNUSED_VARIABLE(aInstance);
     OT_UNUSED_VARIABLE(aDataset);
     OT_UNUSED_VARIABLE(aTlvs);
     OT_UNUSED_VARIABLE(aLength);
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#endif
 
     return error;
 }
@@ -212,10 +233,12 @@
     uint16_t sessionId = 0;
 
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
-    sessionId = aInstance->mThreadNetif.GetCommissioner().GetSessionId();
-#else  // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    sessionId = instance.GetThreadNetif().GetCommissioner().GetSessionId();
+#else
     OT_UNUSED_VARIABLE(aInstance);
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#endif
 
     return sessionId;
 }
@@ -225,10 +248,12 @@
     otCommissionerState state = OT_COMMISSIONER_STATE_DISABLED;
 
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
-    state = aInstance->mThreadNetif.GetCommissioner().GetState();
-#else  // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    state = instance.GetThreadNetif().GetCommissioner().GetState();
+#else
     OT_UNUSED_VARIABLE(aInstance);
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#endif
 
     return state;
 }
@@ -239,14 +264,16 @@
     otError error = OT_ERROR_DISABLED_FEATURE;
 
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
-    error = aInstance->mThreadNetif.GetCommissioner().GeneratePSKc(aPassPhrase, aNetworkName, aExtPanId, aPSKc);
-#else  // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetCommissioner().GeneratePSKc(aPassPhrase, aNetworkName, aExtPanId, aPSKc);
+#else
     OT_UNUSED_VARIABLE(aInstance);
     OT_UNUSED_VARIABLE(aPassPhrase);
     OT_UNUSED_VARIABLE(aNetworkName);
     OT_UNUSED_VARIABLE(aExtPanId);
     OT_UNUSED_VARIABLE(aPSKc);
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
+#endif
 
     return error;
 }
diff --git a/src/core/api/dataset_api.cpp b/src/core/api/dataset_api.cpp
index a84e3a2..dc4f220 100644
--- a/src/core/api/dataset_api.cpp
+++ b/src/core/api/dataset_api.cpp
@@ -35,7 +35,7 @@
 
 #include <openthread/dataset.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
@@ -57,10 +57,11 @@
 otError otDatasetGetActive(otInstance *aInstance, otOperationalDataset *aDataset)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aDataset != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetActiveDataset().GetLocal().Get(*aDataset);
+    error = instance.GetThreadNetif().GetActiveDataset().GetLocal().Get(*aDataset);
 
 exit:
     return error;
@@ -69,10 +70,11 @@
 otError otDatasetGetPending(otInstance *aInstance, otOperationalDataset *aDataset)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aDataset != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetPendingDataset().GetLocal().Get(*aDataset);
+    error = instance.GetThreadNetif().GetPendingDataset().GetLocal().Get(*aDataset);
 
 exit:
     return error;
diff --git a/src/core/api/dataset_ftd_api.cpp b/src/core/api/dataset_ftd_api.cpp
index c231966..5cbed5d 100644
--- a/src/core/api/dataset_ftd_api.cpp
+++ b/src/core/api/dataset_ftd_api.cpp
@@ -37,17 +37,18 @@
 
 #include <openthread/dataset_ftd.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
 otError otDatasetSetActive(otInstance *aInstance, const otOperationalDataset *aDataset)
 {
     otError error;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aDataset != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetActiveDataset().Set(*aDataset);
+    error = instance.GetThreadNetif().GetActiveDataset().Set(*aDataset);
 
 exit:
     return error;
@@ -56,10 +57,11 @@
 otError otDatasetSetPending(otInstance *aInstance, const otOperationalDataset *aDataset)
 {
     otError error;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aDataset != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetPendingDataset().Set(*aDataset);
+    error = instance.GetThreadNetif().GetPendingDataset().Set(*aDataset);
 
 exit:
     return error;
@@ -68,35 +70,47 @@
 otError otDatasetSendMgmtActiveGet(otInstance *aInstance, const uint8_t *aTlvTypes, uint8_t aLength,
                                    const otIp6Address *aAddress)
 {
-    return aInstance->mThreadNetif.GetActiveDataset().SendGetRequest(aTlvTypes, aLength, aAddress);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetActiveDataset().SendGetRequest(aTlvTypes, aLength, aAddress);
 }
 
 otError otDatasetSendMgmtActiveSet(otInstance *aInstance, const otOperationalDataset *aDataset,
                                    const uint8_t *aTlvs, uint8_t aLength)
 {
-    return aInstance->mThreadNetif.GetActiveDataset().SendSetRequest(*aDataset, aTlvs, aLength);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetActiveDataset().SendSetRequest(*aDataset, aTlvs, aLength);
 }
 
 otError otDatasetSendMgmtPendingGet(otInstance *aInstance, const uint8_t *aTlvTypes, uint8_t aLength,
                                     const otIp6Address *aAddress)
 {
-    return aInstance->mThreadNetif.GetPendingDataset().SendGetRequest(aTlvTypes, aLength, aAddress);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetPendingDataset().SendGetRequest(aTlvTypes, aLength, aAddress);
 }
 
 otError otDatasetSendMgmtPendingSet(otInstance *aInstance, const otOperationalDataset *aDataset,
                                     const uint8_t *aTlvs, uint8_t aLength)
 {
-    return aInstance->mThreadNetif.GetPendingDataset().SendSetRequest(*aDataset, aTlvs, aLength);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetPendingDataset().SendSetRequest(*aDataset, aTlvs, aLength);
 }
 
 uint32_t otDatasetGetDelayTimerMinimal(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetLeader().GetDelayTimerMinimal();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetLeader().GetDelayTimerMinimal();
 }
 
 otError otDatasetSetDelayTimerMinimal(otInstance *aInstance, uint32_t aDelayTimerMinimal)
 {
-    return aInstance->mThreadNetif.GetLeader().SetDelayTimerMinimal(aDelayTimerMinimal);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetLeader().SetDelayTimerMinimal(aDelayTimerMinimal);
 }
 
 #endif  // OPENTHREAD_FTD
diff --git a/src/core/api/dhcp6_api.cpp b/src/core/api/dhcp6_api.cpp
index ef307e4..9bb664e 100644
--- a/src/core/api/dhcp6_api.cpp
+++ b/src/core/api/dhcp6_api.cpp
@@ -36,20 +36,24 @@
 #include <openthread/dhcp6_client.h>
 #include <openthread/dhcp6_server.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
 #if OPENTHREAD_ENABLE_DHCP6_CLIENT
 void otDhcp6ClientUpdate(otInstance *aInstance, otDhcpAddress *aAddresses, uint32_t aNumAddresses, void *aContext)
 {
-    aInstance->mThreadNetif.GetDhcp6Client().UpdateAddresses(aInstance, aAddresses, aNumAddresses, aContext);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetDhcp6Client().UpdateAddresses(aInstance, aAddresses, aNumAddresses, aContext);
 }
-#endif  // OPENTHREAD_ENABLE_DHCP6_CLIENT
+#endif
 
 #if OPENTHREAD_ENABLE_DHCP6_SERVER
 void otDhcp6ServerUpdate(otInstance *aInstance)
 {
-    aInstance->mThreadNetif.GetDhcp6Server().UpdateService();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetDhcp6Server().UpdateService();
 }
-#endif  // OPENTHREAD_ENABLE_DHCP6_SERVER
+#endif
diff --git a/src/core/api/dns_api.cpp b/src/core/api/dns_api.cpp
index 14294f9..54e5be3 100644
--- a/src/core/api/dns_api.cpp
+++ b/src/core/api/dns_api.cpp
@@ -35,7 +35,7 @@
 
 #include <openthread/dns.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
@@ -43,6 +43,8 @@
 otError otDnsClientQuery(otInstance *aInstance, const otDnsQuery *aQuery, otDnsResponseHandler aHandler,
                          void *aContext)
 {
-    return aInstance->mThreadNetif.GetDnsClient().Query(aQuery, aHandler, aContext);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetDnsClient().Query(aQuery, aHandler, aContext);
 }
-#endif  // OPENTHREAD_ENABLE_DNS_CLIENT
+#endif
diff --git a/src/core/api/icmp6_api.cpp b/src/core/api/icmp6_api.cpp
index 7d5aed4..7196005 100644
--- a/src/core/api/icmp6_api.cpp
+++ b/src/core/api/icmp6_api.cpp
@@ -35,29 +35,37 @@
 
 #include <openthread/icmp6.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
 bool otIcmp6IsEchoEnabled(otInstance *aInstance)
 {
-    return aInstance->mIp6.GetIcmp().IsEchoEnabled();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetIp6().GetIcmp().IsEchoEnabled();
 }
 
 void otIcmp6SetEchoEnabled(otInstance *aInstance, bool aEnabled)
 {
-    aInstance->mIp6.GetIcmp().SetEchoEnabled(aEnabled);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetIp6().GetIcmp().SetEchoEnabled(aEnabled);
 }
 
 otError otIcmp6RegisterHandler(otInstance *aInstance, otIcmp6Handler *aHandler)
 {
-    return aInstance->mIp6.GetIcmp().RegisterHandler(*static_cast<Ip6::IcmpHandler *>(aHandler));
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetIp6().GetIcmp().RegisterHandler(*static_cast<Ip6::IcmpHandler *>(aHandler));
 }
 
 otError otIcmp6SendEchoRequest(otInstance *aInstance, otMessage *aMessage,
                                const otMessageInfo *aMessageInfo, uint16_t aIdentifier)
 {
-    return aInstance->mIp6.GetIcmp().SendEchoRequest(*static_cast<Message *>(aMessage),
-                                                     *static_cast<const Ip6::MessageInfo *>(aMessageInfo),
-                                                     aIdentifier);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetIp6().GetIcmp().SendEchoRequest(*static_cast<Message *>(aMessage),
+                                                       *static_cast<const Ip6::MessageInfo *>(aMessageInfo),
+                                                       aIdentifier);
 }
diff --git a/src/core/api/instance_api.cpp b/src/core/api/instance_api.cpp
index 53c4140..b2f3bf3 100644
--- a/src/core/api/instance_api.cpp
+++ b/src/core/api/instance_api.cpp
@@ -39,227 +39,81 @@
 #include <openthread/platform/misc.h>
 #include <openthread/platform/settings.h>
 
-#include "openthread-instance.h"
-#include "openthread-single-instance.h"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/new.hpp"
 
-#if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
-
-static otDEFINE_ALIGNED_VAR(sInstanceRaw, sizeof(otInstance), uint64_t);
-otInstance *sInstance = NULL;
-
-otInstance *otGetInstance(void)
-{
-    return sInstance;
-}
-
-ot::ThreadNetif &otGetThreadNetif(void)
-{
-    return sInstance->mThreadNetif;
-}
-
-ot::MeshForwarder &otGetMeshForwarder(void)
-{
-    return sInstance->mThreadNetif.GetMeshForwarder();
-}
-
-ot::TaskletScheduler &otGetTaskletScheduler(void)
-{
-    return sInstance->mTaskletScheduler;
-}
-
-ot::Ip6::Ip6 &otGetIp6(void)
-{
-    return sInstance->mIp6;
-}
-#endif // #if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
-
-otInstance::otInstance(void) :
-    mReceiveIp6DatagramCallback(NULL),
-    mReceiveIp6DatagramCallbackContext(NULL),
-    mActiveScanCallback(NULL),
-    mActiveScanCallbackContext(NULL),
-    mEnergyScanCallback(NULL),
-    mEnergyScanCallbackContext(NULL),
-    mTimerMilliScheduler(*this),
-#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
-    mTimerMicroScheduler(*this),
-#endif
-    mIp6(*this),
-    mThreadNetif(*this),
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-    mLinkRaw(*this),
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
-#if OPENTHREAD_ENABLE_APPLICATION_COAP
-    mApplicationCoap(*this),
-#endif // OPENTHREAD_ENABLE_APPLICATION_COAP
-#if OPENTHREAD_CONFIG_ENABLE_DYNAMIC_LOG_LEVEL
-    mLogLevel(static_cast<otLogLevel>(OPENTHREAD_CONFIG_LOG_LEVEL)),
-#endif // OPENTHREAD_CONFIG_ENABLE_DYNAMIC_LOG_LEVEL
-    mMessagePool(*this)
-{
-}
-
 using namespace ot;
 
-void otInstancePostConstructor(otInstance *aInstance)
-{
-    // restore datasets and network information
-    otPlatSettingsInit(aInstance);
-    aInstance->mThreadNetif.GetMle().Restore();
-
-#if OPENTHREAD_CONFIG_ENABLE_AUTO_START_SUPPORT
-
-    // If auto start is configured, do that now
-    if (otThreadGetAutoStart(aInstance))
-    {
-        if (otIp6SetEnabled(aInstance, true) == OT_ERROR_NONE)
-        {
-            // Only try to start Thread if we could bring up the interface
-            if (otThreadSetEnabled(aInstance, true) != OT_ERROR_NONE)
-            {
-                // Bring the interface down if Thread failed to start
-                otIp6SetEnabled(aInstance, false);
-            }
-        }
-    }
-
-#endif
-}
-
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
-
 otInstance *otInstanceInit(void *aInstanceBuffer, size_t *aInstanceBufferSize)
 {
-    otInstance *instance = NULL;
+    Instance *instance;
 
     otLogFuncEntry();
-
-    VerifyOrExit(aInstanceBufferSize != NULL);
-
-    // Make sure the input buffer is big enough
-    VerifyOrExit(sizeof(otInstance) <= *aInstanceBufferSize, *aInstanceBufferSize = sizeof(otInstance));
-
-    VerifyOrExit(aInstanceBuffer != NULL);
-
-    // Construct the context
-    instance = new(aInstanceBuffer)otInstance();
-
-    // Execute post constructor operations
-    otInstancePostConstructor(instance);
-
+    instance = Instance::Init(aInstanceBuffer, aInstanceBufferSize);
     otLogInfoApi(*instance, "otInstance Initialized");
-
-exit:
-
     otLogFuncExit();
+
     return instance;
 }
-
-bool otInstanceIsInitialized(otInstance *aInstance)
-{
-    return (aInstance != NULL);
-}
-
-#else // #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
-
+#else
 otInstance *otInstanceInitSingle(void)
 {
-    otLogFuncEntry();
-
-    VerifyOrExit(sInstance == NULL);
-
-    // We need to ensure `sInstance` pointer is correctly set
-    // before any object constructor is called.
-    sInstance = reinterpret_cast<otInstance *>(&sInstanceRaw);
-
-    // Construct the context
-    sInstance = new(&sInstanceRaw)otInstance();
-
-    // Execute post constructor operations
-    otInstancePostConstructor(sInstance);
-
-    otLogInfoApi(*sInstance, "otInstance Initialized");
-
-exit:
-
-    otLogFuncExit();
-    return sInstance;
+    return &Instance::InitSingle();
 }
+#endif // #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
+
 
 bool otInstanceIsInitialized(otInstance *aInstance)
 {
-    return (aInstance != NULL) && (aInstance == sInstance);
-}
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-#endif // #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
+    return instance.IsInitialized();
+}
 
 void otInstanceFinalize(otInstance *aInstance)
 {
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
     otLogFuncEntry();
-
-    // Ensure we are disabled
-    (void)otThreadSetEnabled(aInstance, false);
-    (void)otIp6SetEnabled(aInstance, false);
-
-#if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
-    sInstance = NULL;
-#endif
-
+    instance.Finalize();
     otLogFuncExit();
 }
 
 otError otSetStateChangedCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aCallbackContext)
 {
-    otError error = OT_ERROR_NO_BUFS;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    for (size_t i = 0; i < OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS; i++)
-    {
-        if (aInstance->mNetifCallback[i].IsFree())
-        {
-            aInstance->mNetifCallback[i].Set(aCallback, aCallbackContext);
-            error = aInstance->mThreadNetif.RegisterCallback(aInstance->mNetifCallback[i]);
-            break;
-        }
-    }
-
-    return error;
+    return instance.RegisterStateChangedCallback(aCallback, aCallbackContext);
 }
 
 void otRemoveStateChangeCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aCallbackContext)
 {
-    for (size_t i = 0; i < OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS; i++)
-    {
-        if (aInstance->mNetifCallback[i].IsServing(aCallback, aCallbackContext))
-        {
-            aInstance->mThreadNetif.RemoveCallback(aInstance->mNetifCallback[i]);
-            aInstance->mNetifCallback[i].Free();
-            break;
-        }
-    }
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.RemoveStateChangedCallback(aCallback, aCallbackContext);
 }
 
 void otInstanceReset(otInstance *aInstance)
 {
-    otPlatReset(aInstance);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.Reset();
 }
 
 void otInstanceFactoryReset(otInstance *aInstance)
 {
-    otPlatSettingsWipe(aInstance);
-    otPlatReset(aInstance);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.FactoryReset();
 }
 
 otError otInstanceErasePersistentInfo(otInstance *aInstance)
 {
-    otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(otThreadGetDeviceRole(aInstance) ==  OT_DEVICE_ROLE_DISABLED, error = OT_ERROR_INVALID_STATE);
-    otPlatSettingsWipe(aInstance);
-
-exit:
-    return error;
+    return instance.ErasePersistentInfo();
 }
 
 otLogLevel otGetDynamicLogLevel(otInstance *aInstance)
@@ -267,7 +121,9 @@
     otLogLevel logLevel;
 
 #if OPENTHREAD_CONFIG_ENABLE_DYNAMIC_LOG_LEVEL
-    logLevel =  aInstance->mLogLevel;
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    logLevel = instance.GetDynamicLogLevel();
 #else
     logLevel = static_cast<otLogLevel>(OPENTHREAD_CONFIG_LOG_LEVEL);
     OT_UNUSED_VARIABLE(aInstance);
@@ -281,7 +137,9 @@
     otError error = OT_ERROR_NONE;
 
 #if OPENTHREAD_CONFIG_ENABLE_DYNAMIC_LOG_LEVEL
-    aInstance->mLogLevel = aLogLevel;
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.SetDynamicLogLevel(aLogLevel);
 #else
     error = OT_ERROR_DISABLED_FEATURE;
     OT_UNUSED_VARIABLE(aInstance);
diff --git a/src/core/api/ip6_api.cpp b/src/core/api/ip6_api.cpp
index a811db4..ebf3a96 100644
--- a/src/core/api/ip6_api.cpp
+++ b/src/core/api/ip6_api.cpp
@@ -37,7 +37,7 @@
 
 #include <openthread/ip6.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "utils/slaac_address.hpp"
 
@@ -46,22 +46,23 @@
 otError otIp6SetEnabled(otInstance *aInstance, bool aEnabled)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     otLogFuncEntry();
 
     if (aEnabled)
     {
 #if OPENTHREAD_ENABLE_RAW_LINK_API
-        VerifyOrExit(!aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+        VerifyOrExit(!instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 #endif // OPENTHREAD_ENABLE_RAW_LINK_API
-        error = aInstance->mThreadNetif.Up();
+        error = instance.GetThreadNetif().Up();
     }
     else
     {
 #if OPENTHREAD_ENABLE_RAW_LINK_API
-        VerifyOrExit(!aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+        VerifyOrExit(!instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 #endif // OPENTHREAD_ENABLE_RAW_LINK_API
-        error = aInstance->mThreadNetif.Down();
+        error = instance.GetThreadNetif().Down();
     }
 
 #if OPENTHREAD_ENABLE_RAW_LINK_API
@@ -73,47 +74,65 @@
 
 bool otIp6IsEnabled(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.IsUp();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().IsUp();
 }
 
 const otNetifAddress *otIp6GetUnicastAddresses(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetUnicastAddresses();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetUnicastAddresses();
 }
 
 otError otIp6AddUnicastAddress(otInstance *aInstance, const otNetifAddress *address)
 {
-    return aInstance->mThreadNetif.AddExternalUnicastAddress(*static_cast<const Ip6::NetifUnicastAddress *>(address));
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().AddExternalUnicastAddress(*static_cast<const Ip6::NetifUnicastAddress *>(address));
 }
 
 otError otIp6RemoveUnicastAddress(otInstance *aInstance, const otIp6Address *address)
 {
-    return aInstance->mThreadNetif.RemoveExternalUnicastAddress(*static_cast<const Ip6::Address *>(address));
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().RemoveExternalUnicastAddress(*static_cast<const Ip6::Address *>(address));
 }
 
 const otNetifMulticastAddress *otIp6GetMulticastAddresses(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMulticastAddresses();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMulticastAddresses();
 }
 
 otError otIp6SubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aAddress)
 {
-    return aInstance->mThreadNetif.SubscribeExternalMulticast(*static_cast<const Ip6::Address *>(aAddress));
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().SubscribeExternalMulticast(*static_cast<const Ip6::Address *>(aAddress));
 }
 
 otError otIp6UnsubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aAddress)
 {
-    return aInstance->mThreadNetif.UnsubscribeExternalMulticast(*static_cast<const Ip6::Address *>(aAddress));
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().UnsubscribeExternalMulticast(*static_cast<const Ip6::Address *>(aAddress));
 }
 
 bool otIp6IsMulticastPromiscuousEnabled(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.IsMulticastPromiscuousEnabled();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().IsMulticastPromiscuousEnabled();
 }
 
 void otIp6SetMulticastPromiscuousEnabled(otInstance *aInstance, bool aEnabled)
 {
-    aInstance->mThreadNetif.SetMulticastPromiscuous(aEnabled);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().SetMulticastPromiscuous(aEnabled);
 }
 
 void otIp6SlaacUpdate(otInstance *aInstance, otNetifAddress *aAddresses, uint32_t aNumAddresses,
@@ -129,8 +148,10 @@
 
 otError otIp6CreateMacIid(otInstance *aInstance, otNetifAddress *aAddress, void *)
 {
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
     memcpy(&aAddress->mAddress.mFields.m8[OT_IP6_ADDRESS_SIZE - OT_IP6_IID_SIZE],
-           aInstance->mThreadNetif.GetMac().GetExtAddress(), OT_IP6_IID_SIZE);
+           instance.GetThreadNetif().GetMac().GetExtAddress(), OT_IP6_IID_SIZE);
     aAddress->mAddress.mFields.m8[OT_IP6_ADDRESS_SIZE - OT_IP6_IID_SIZE] ^= 0x02;
 
     return OT_ERROR_NONE;
@@ -143,27 +164,34 @@
 
 void otIp6SetReceiveCallback(otInstance *aInstance, otIp6ReceiveCallback aCallback, void *aCallbackContext)
 {
-    aInstance->mIp6.SetReceiveDatagramCallback(aCallback, aCallbackContext);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetIp6().SetReceiveDatagramCallback(aCallback, aCallbackContext);
 }
 
 bool otIp6IsReceiveFilterEnabled(otInstance *aInstance)
 {
-    return aInstance->mIp6.IsReceiveIp6FilterEnabled();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetIp6().IsReceiveIp6FilterEnabled();
 }
 
 void otIp6SetReceiveFilterEnabled(otInstance *aInstance, bool aEnabled)
 {
-    aInstance->mIp6.SetReceiveIp6FilterEnabled(aEnabled);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetIp6().SetReceiveIp6FilterEnabled(aEnabled);
 }
 
 otError otIp6Send(otInstance *aInstance, otMessage *aMessage)
 {
     otError error;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     otLogFuncEntry();
 
-    error = aInstance->mIp6.SendRaw(*static_cast<Message *>(aMessage),
-                                    aInstance->mThreadNetif.GetInterfaceId());
+    error = instance.GetIp6().SendRaw(*static_cast<Message *>(aMessage),
+                                      instance.GetThreadNetif().GetInterfaceId());
 
     otLogFuncExitErr(error);
 
@@ -172,7 +200,9 @@
 
 otMessage *otIp6NewMessage(otInstance *aInstance, bool aLinkSecurityEnabled)
 {
-    Message *message = aInstance->mMessagePool.New(Message::kTypeIp6, 0);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+    Message *message = instance.GetMessagePool().New(Message::kTypeIp6, 0);
+
 
     if (message)
     {
@@ -184,17 +214,23 @@
 
 otError otIp6AddUnsecurePort(otInstance *aInstance, uint16_t aPort)
 {
-    return aInstance->mThreadNetif.GetIp6Filter().AddUnsecurePort(aPort);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetIp6Filter().AddUnsecurePort(aPort);
 }
 
 otError otIp6RemoveUnsecurePort(otInstance *aInstance, uint16_t aPort)
 {
-    return aInstance->mThreadNetif.GetIp6Filter().RemoveUnsecurePort(aPort);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetIp6Filter().RemoveUnsecurePort(aPort);
 }
 
 const uint16_t *otIp6GetUnsecurePorts(otInstance *aInstance, uint8_t *aNumEntries)
 {
-    return aInstance->mThreadNetif.GetIp6Filter().GetUnsecurePorts(*aNumEntries);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetIp6Filter().GetUnsecurePorts(*aNumEntries);
 }
 
 bool otIp6IsAddressEqual(const otIp6Address *a, const otIp6Address *b)
diff --git a/src/core/api/jam_detection_api.cpp b/src/core/api/jam_detection_api.cpp
index a77b7cc..57893c0 100644
--- a/src/core/api/jam_detection_api.cpp
+++ b/src/core/api/jam_detection_api.cpp
@@ -35,7 +35,7 @@
 
 #include <openthread/jam_detection.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
@@ -43,57 +43,79 @@
 
 otError otJamDetectionSetRssiThreshold(otInstance *aInstance, int8_t aRssiThreshold)
 {
-    return aInstance->mThreadNetif.GetJamDetector().SetRssiThreshold(aRssiThreshold);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetJamDetector().SetRssiThreshold(aRssiThreshold);
 }
 
 int8_t otJamDetectionGetRssiThreshold(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetJamDetector().GetRssiThreshold();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetJamDetector().GetRssiThreshold();
 }
 
 otError otJamDetectionSetWindow(otInstance *aInstance, uint8_t aWindow)
 {
-    return aInstance->mThreadNetif.GetJamDetector().SetWindow(aWindow);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetJamDetector().SetWindow(aWindow);
 }
 
 uint8_t otJamDetectionGetWindow(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetJamDetector().GetWindow();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetJamDetector().GetWindow();
 }
 
 otError otJamDetectionSetBusyPeriod(otInstance *aInstance, uint8_t aBusyPeriod)
 {
-    return aInstance->mThreadNetif.GetJamDetector().SetBusyPeriod(aBusyPeriod);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetJamDetector().SetBusyPeriod(aBusyPeriod);
 }
 
 uint8_t otJamDetectionGetBusyPeriod(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetJamDetector().GetBusyPeriod();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetJamDetector().GetBusyPeriod();
 }
 
 otError otJamDetectionStart(otInstance *aInstance, otJamDetectionCallback aCallback, void *aContext)
 {
-    return aInstance->mThreadNetif.GetJamDetector().Start(aCallback, aContext);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetJamDetector().Start(aCallback, aContext);
 }
 
 otError otJamDetectionStop(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetJamDetector().Stop();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetJamDetector().Stop();
 }
 
 bool otJamDetectionIsEnabled(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetJamDetector().IsEnabled();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetJamDetector().IsEnabled();
 }
 
 bool otJamDetectionGetState(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetJamDetector().GetState();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetJamDetector().GetState();
 }
 
 uint64_t otJamDetectionGetHistoryBitmap(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetJamDetector().GetHistoryBitmap();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetJamDetector().GetHistoryBitmap();
 }
 
 #endif  // OPENTHREAD_ENABLE_JAM_DETECTION
diff --git a/src/core/api/joiner_api.cpp b/src/core/api/joiner_api.cpp
index 8680efc..df3fba6 100644
--- a/src/core/api/joiner_api.cpp
+++ b/src/core/api/joiner_api.cpp
@@ -35,7 +35,7 @@
 
 #include <openthread/joiner.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
@@ -45,11 +45,11 @@
                       otJoinerCallback aCallback, void *aContext)
 {
     otError error = OT_ERROR_DISABLED_FEATURE;
-
 #if OPENTHREAD_ENABLE_JOINER
-    error = aInstance->mThreadNetif.GetJoiner().Start(aPSKd, aProvisioningUrl,
-                                                      aVendorName, aVendorModel, aVendorSwVersion, aVendorData,
-                                                      aCallback, aContext);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetJoiner().Start(aPSKd, aProvisioningUrl, aVendorName, aVendorModel,
+                                                        aVendorSwVersion, aVendorData, aCallback, aContext);
 #else
     OT_UNUSED_VARIABLE(aInstance);
     OT_UNUSED_VARIABLE(aPSKd);
@@ -70,7 +70,9 @@
     otError error = OT_ERROR_DISABLED_FEATURE;
 
 #if OPENTHREAD_ENABLE_JOINER
-    error = aInstance->mThreadNetif.GetJoiner().Stop();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetJoiner().Stop();
 #else
     OT_UNUSED_VARIABLE(aInstance);
 #endif
@@ -83,7 +85,9 @@
     otJoinerState state = OT_JOINER_STATE_IDLE;
 
 #if OPENTHREAD_ENABLE_JOINER
-    state = aInstance->mThreadNetif.GetJoiner().GetState();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    state = instance.GetThreadNetif().GetJoiner().GetState();
 #else
     OT_UNUSED_VARIABLE(aInstance);
 #endif
@@ -96,7 +100,9 @@
     otError error = OT_ERROR_DISABLED_FEATURE;
 
 #if OPENTHREAD_ENABLE_JOINER
-    aInstance->mThreadNetif.GetJoiner().GetJoinerId(*static_cast<Mac::ExtAddress *>(aJoinerId));
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetJoiner().GetJoinerId(*static_cast<Mac::ExtAddress *>(aJoinerId));
     error = OT_ERROR_NONE;
 #else
     OT_UNUSED_VARIABLE(aInstance);
diff --git a/src/core/api/link_api.cpp b/src/core/api/link_api.cpp
index c9217a3..4d7482a 100644
--- a/src/core/api/link_api.cpp
+++ b/src/core/api/link_api.cpp
@@ -35,7 +35,7 @@
 
 #include <openthread/link.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
@@ -44,19 +44,22 @@
 
 uint8_t otLinkGetChannel(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMac().GetChannel();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().GetChannel();
 }
 
 otError otLinkSetChannel(otInstance *aInstance, uint8_t aChannel)
 {
     otError error;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mThreadNetif.GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
+    VerifyOrExit(instance.GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
                  error = OT_ERROR_INVALID_STATE);
 
-    SuccessOrExit(error = aInstance->mThreadNetif.GetMac().SetChannel(aChannel));
-    aInstance->mThreadNetif.GetActiveDataset().Clear();
-    aInstance->mThreadNetif.GetPendingDataset().Clear();
+    SuccessOrExit(error = instance.GetThreadNetif().GetMac().SetChannel(aChannel));
+    instance.GetThreadNetif().GetActiveDataset().Clear();
+    instance.GetThreadNetif().GetPendingDataset().Clear();
 
 exit:
     return error;
@@ -64,20 +67,23 @@
 
 const otExtAddress *otLinkGetExtendedAddress(otInstance *aInstance)
 {
-    return reinterpret_cast<const otExtAddress *>(aInstance->mThreadNetif.GetMac().GetExtAddress());
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return reinterpret_cast<const otExtAddress *>(instance.GetThreadNetif().GetMac().GetExtAddress());
 }
 
 otError otLinkSetExtendedAddress(otInstance *aInstance, const otExtAddress *aExtAddress)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aExtAddress != NULL, error = OT_ERROR_INVALID_ARGS);
-    VerifyOrExit(aInstance->mThreadNetif.GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
+    VerifyOrExit(instance.GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
                  error = OT_ERROR_INVALID_STATE);
 
-    aInstance->mThreadNetif.GetMac().SetExtAddress(*static_cast<const Mac::ExtAddress *>(aExtAddress));
+    instance.GetThreadNetif().GetMac().SetExtAddress(*static_cast<const Mac::ExtAddress *>(aExtAddress));
 
-    SuccessOrExit(error = aInstance->mThreadNetif.GetMle().UpdateLinkLocalAddress());
+    SuccessOrExit(error = instance.GetThreadNetif().GetMle().UpdateLinkLocalAddress());
 
 exit:
     return error;
@@ -90,30 +96,37 @@
 
 int8_t otLinkGetMaxTransmitPower(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMac().GetMaxTransmitPower();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().GetMaxTransmitPower();
 }
 
 void otLinkSetMaxTransmitPower(otInstance *aInstance, int8_t aPower)
 {
-    aInstance->mThreadNetif.GetMac().SetMaxTransmitPower(aPower);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetMac().SetMaxTransmitPower(aPower);
     otPlatRadioSetDefaultTxPower(aInstance, aPower);
 }
 
 otPanId otLinkGetPanId(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMac().GetPanId();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().GetPanId();
 }
 
 otError otLinkSetPanId(otInstance *aInstance, otPanId aPanId)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mThreadNetif.GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
+    VerifyOrExit(instance.GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
                  error = OT_ERROR_INVALID_STATE);
 
-    error = aInstance->mThreadNetif.GetMac().SetPanId(aPanId);
-    aInstance->mThreadNetif.GetActiveDataset().Clear();
-    aInstance->mThreadNetif.GetPendingDataset().Clear();
+    error = instance.GetThreadNetif().GetMac().SetPanId(aPanId);
+    instance.GetThreadNetif().GetActiveDataset().Clear();
+    instance.GetThreadNetif().GetPendingDataset().Clear();
 
 exit:
     return error;
@@ -121,43 +134,56 @@
 
 uint32_t otLinkGetPollPeriod(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMeshForwarder().GetDataPollManager().GetKeepAlivePollPeriod();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMeshForwarder().GetDataPollManager().GetKeepAlivePollPeriod();
 }
 
 void otLinkSetPollPeriod(otInstance *aInstance, uint32_t aPollPeriod)
 {
-    aInstance->mThreadNetif.GetMeshForwarder().GetDataPollManager().SetExternalPollPeriod(aPollPeriod);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetMeshForwarder().GetDataPollManager().SetExternalPollPeriod(aPollPeriod);
 }
 
 otError otLinkSendDataRequest(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMeshForwarder().GetDataPollManager().SendDataPoll();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMeshForwarder().GetDataPollManager().SendDataPoll();
 }
 
 otShortAddress otLinkGetShortAddress(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMac().GetShortAddress();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().GetShortAddress();
 }
 
 #if OPENTHREAD_ENABLE_MAC_FILTER
 
 otMacFilterAddressMode otLinkFilterGetAddressMode(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMac().GetFilter().GetAddressMode();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().GetFilter().GetAddressMode();
 }
 
 otError otLinkFilterSetAddressMode(otInstance *aInstance, otMacFilterAddressMode aMode)
 {
-    return aInstance->mThreadNetif.GetMac().GetFilter().SetAddressMode(aMode);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().GetFilter().SetAddressMode(aMode);
 }
 
 otError otLinkFilterAddAddress(otInstance *aInstance, const otExtAddress *aExtAddress)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aExtAddress != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetMac().GetFilter().AddAddress(*static_cast<const Mac::ExtAddress *>(aExtAddress));
+    error = instance.GetThreadNetif().GetMac().GetFilter().AddAddress(*static_cast<const Mac::ExtAddress *>(aExtAddress));
 
 exit:
     return error;
@@ -166,10 +192,11 @@
 otError otLinkFilterRemoveAddress(otInstance *aInstance, const otExtAddress *aExtAddress)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aExtAddress != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetMac().GetFilter().RemoveAddress(
+    error = instance.GetThreadNetif().GetMac().GetFilter().RemoveAddress(
                 *static_cast<const Mac::ExtAddress *>(aExtAddress));
 
 exit:
@@ -178,17 +205,19 @@
 
 void otLinkFilterClearAddresses(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMac().GetFilter().ClearAddresses();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().GetFilter().ClearAddresses();
 }
 
 otError otLinkFilterGetNextAddress(otInstance *aInstance, otMacFilterIterator *aIterator, otMacFilterEntry *aEntry)
 {
-
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aIterator != NULL && aEntry != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetMac().GetFilter().GetNextAddress(*aIterator, *aEntry);
+    error = instance.GetThreadNetif().GetMac().GetFilter().GetNextAddress(*aIterator, *aEntry);
 
 exit:
     return error;
@@ -196,27 +225,34 @@
 
 otError otLinkFilterAddRssIn(otInstance *aInstance, const otExtAddress *aExtAddress, int8_t aRss)
 {
-    return aInstance->mThreadNetif.GetMac().GetFilter().AddRssIn(
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().GetFilter().AddRssIn(
                static_cast<const Mac::ExtAddress *>(aExtAddress), aRss);
 }
 
 otError otLinkFilterRemoveRssIn(otInstance *aInstance, const otExtAddress *aExtAddress)
 {
-    return aInstance->mThreadNetif.GetMac().GetFilter().RemoveRssIn(static_cast<const Mac::ExtAddress *>(aExtAddress));
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().GetFilter().RemoveRssIn(static_cast<const Mac::ExtAddress *>(aExtAddress));
 }
 
 void otLinkFilterClearRssIn(otInstance *aInstance)
 {
-    aInstance->mThreadNetif.GetMac().GetFilter().ClearRssIn();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetMac().GetFilter().ClearRssIn();
 }
 
 otError otLinkFilterGetNextRssIn(otInstance *aInstance, otMacFilterIterator *aIterator, otMacFilterEntry *aEntry)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aIterator != NULL && aEntry != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetMac().GetFilter().GetNextRssIn(*aIterator, *aEntry);
+    error = instance.GetThreadNetif().GetMac().GetFilter().GetNextRssIn(*aIterator, *aEntry);
 
 exit:
     return error;
@@ -224,34 +260,43 @@
 
 uint8_t otLinkConvertRssToLinkQuality(otInstance *aInstance, int8_t aRss)
 {
-    return LinkQualityInfo::ConvertRssToLinkQuality(aInstance->mThreadNetif.GetMac().GetNoiseFloor(), aRss);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return LinkQualityInfo::ConvertRssToLinkQuality(instance.GetThreadNetif().GetMac().GetNoiseFloor(), aRss);
 }
 
 int8_t otLinkConvertLinkQualityToRss(otInstance *aInstance, uint8_t aLinkQuality)
 {
-    return LinkQualityInfo::ConvertLinkQualityToRss(aInstance->mThreadNetif.GetMac().GetNoiseFloor(), aLinkQuality);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return LinkQualityInfo::ConvertLinkQualityToRss(instance.GetThreadNetif().GetMac().GetNoiseFloor(), aLinkQuality);
 }
 
 #endif  // OPENTHREAD_ENABLE_MAC_FILTER
 
 void otLinkSetPcapCallback(otInstance *aInstance, otLinkPcapCallback aPcapCallback, void *aCallbackContext)
 {
-    aInstance->mThreadNetif.GetMac().SetPcapCallback(aPcapCallback, aCallbackContext);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetMac().SetPcapCallback(aPcapCallback, aCallbackContext);
 }
 
 bool otLinkIsPromiscuous(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMac().IsPromiscuous();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().IsPromiscuous();
 }
 
 otError otLinkSetPromiscuous(otInstance *aInstance, bool aPromiscuous)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     // cannot enable IEEE 802.15.4 promiscuous mode if the Thread interface is enabled
-    VerifyOrExit(aInstance->mThreadNetif.IsUp() == false, error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(instance.GetThreadNetif().IsUp() == false, error = OT_ERROR_INVALID_STATE);
 
-    aInstance->mThreadNetif.GetMac().SetPromiscuous(aPromiscuous);
+    instance.GetThreadNetif().GetMac().SetPromiscuous(aPromiscuous);
 
 exit:
     return error;
@@ -259,58 +304,72 @@
 
 const otMacCounters *otLinkGetCounters(otInstance *aInstance)
 {
-    return &aInstance->mThreadNetif.GetMac().GetCounters();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return &instance.GetThreadNetif().GetMac().GetCounters();
 }
 
 otError otLinkActiveScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration,
                          otHandleActiveScanResult aCallback, void *aCallbackContext)
 {
-    aInstance->mActiveScanCallback = aCallback;
-    aInstance->mActiveScanCallbackContext = aCallbackContext;
-    return aInstance->mThreadNetif.GetMac().ActiveScan(aScanChannels, aScanDuration,
-                                                       &HandleActiveScanResult, aInstance);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.RegisterActiveScanCallback(aCallback, aCallbackContext);
+    return instance.GetThreadNetif().GetMac().ActiveScan(aScanChannels, aScanDuration,
+                                                         &HandleActiveScanResult, aInstance);
 }
 
 bool otLinkIsActiveScanInProgress(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMac().IsActiveScanInProgress();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().IsActiveScanInProgress();
 }
 
 void HandleActiveScanResult(void *aContext, Mac::Frame *aFrame)
 {
-    otInstance *aInstance = static_cast<otInstance *>(aContext);
-    otActiveScanResult result;
+    Instance &instance = *static_cast<Instance *>(aContext);
 
-    VerifyOrExit(aFrame != NULL, aInstance->mActiveScanCallback(NULL, aInstance->mActiveScanCallbackContext));
-    aInstance->mThreadNetif.GetMac().ConvertBeaconToActiveScanResult(aFrame, result);
-    aInstance->mActiveScanCallback(&result, aInstance->mActiveScanCallbackContext);
+    if (aFrame == NULL)
+    {
+        instance.InvokeActiveScanCallback(NULL);
+    }
+    else
+    {
+        otActiveScanResult result;
 
-exit:
-    return;
+        instance.GetThreadNetif().GetMac().ConvertBeaconToActiveScanResult(aFrame, result);
+        instance.InvokeActiveScanCallback(&result);
+    }
 }
 
 otError otLinkEnergyScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration,
                          otHandleEnergyScanResult aCallback, void *aCallbackContext)
 {
-    aInstance->mEnergyScanCallback = aCallback;
-    aInstance->mEnergyScanCallbackContext = aCallbackContext;
-    return aInstance->mThreadNetif.GetMac().EnergyScan(aScanChannels, aScanDuration,
-                                                       &HandleEnergyScanResult, aInstance);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.RegisterEnergyScanCallback(aCallback, aCallbackContext);
+    return instance.GetThreadNetif().GetMac().EnergyScan(aScanChannels, aScanDuration,
+                                                         &HandleEnergyScanResult, aInstance);
 }
 
 void HandleEnergyScanResult(void *aContext, otEnergyScanResult *aResult)
 {
-    otInstance *aInstance = static_cast<otInstance *>(aContext);
+    Instance &instance = *static_cast<Instance *>(aContext);
 
-    aInstance->mEnergyScanCallback(aResult, aInstance->mEnergyScanCallbackContext);
+    instance.InvokeEnergyScanCallback(aResult);
 }
 
 bool otLinkIsEnergyScanInProgress(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMac().IsEnergyScanInProgress();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().IsEnergyScanInProgress();
 }
 
 bool otLinkIsInTransmitState(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMac().IsInTransmitState();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().IsInTransmitState();
 }
diff --git a/src/core/api/link_raw.hpp b/src/core/api/link_raw.hpp
index dbc116b..5304671 100644
--- a/src/core/api/link_raw.hpp
+++ b/src/core/api/link_raw.hpp
@@ -55,7 +55,7 @@
      * This constructor initializes the object.
      *
      */
-    LinkRaw(otInstance &aInstance);
+    LinkRaw(Instance &aInstance);
 
     /**
      * This method returns true if the raw link-layer is enabled.
diff --git a/src/core/api/link_raw_api.cpp b/src/core/api/link_raw_api.cpp
index 3b5134f..ee32056 100644
--- a/src/core/api/link_raw_api.cpp
+++ b/src/core/api/link_raw_api.cpp
@@ -35,21 +35,24 @@
 
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 
+using namespace ot;
+
 #if OPENTHREAD_ENABLE_RAW_LINK_API
 
 otError otLinkRawSetEnable(otInstance *aInstance, bool aEnabled)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(!aInstance->mThreadNetif.IsUp(), error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(!instance.GetThreadNetif().IsUp(), error = OT_ERROR_INVALID_STATE);
 
     otLogInfoPlat(aInstance, "LinkRaw Enabled=%d", aEnabled ? 1 : 0);
 
-    aInstance->mLinkRaw.SetEnabled(aEnabled);
+    instance.GetLinkRaw().SetEnabled(aEnabled);
 
 exit:
     return error;
@@ -57,14 +60,17 @@
 
 bool otLinkRawIsEnabled(otInstance *aInstance)
 {
-    return aInstance->mLinkRaw.IsEnabled();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetLinkRaw().IsEnabled();
 }
 
 otError otLinkRawSetPanId(otInstance *aInstance, uint16_t aPanId)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 
     otPlatRadioSetPanId(aInstance, aPanId);
 
@@ -75,9 +81,10 @@
 otError otLinkRawSetExtendedAddress(otInstance *aInstance, const otExtAddress *aExtAddress)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
     otExtAddress address;
 
-    VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 
     for (size_t i = 0; i < sizeof(address); i++)
     {
@@ -93,8 +100,9 @@
 otError otLinkRawSetShortAddress(otInstance *aInstance, uint16_t aShortAddress)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 
     otPlatRadioSetShortAddress(aInstance, aShortAddress);
 
@@ -110,8 +118,9 @@
 otError otLinkRawSetPromiscuous(otInstance *aInstance, bool aEnable)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 
     otLogInfoPlat(aInstance, "LinkRaw Promiscuous=%d", aEnable ? 1 : 0);
 
@@ -124,8 +133,9 @@
 otError otLinkRawSleep(otInstance *aInstance)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 
     otLogInfoPlat(aInstance, "LinkRaw Sleep");
 
@@ -137,15 +147,18 @@
 
 otError otLinkRawReceive(otInstance *aInstance, uint8_t aChannel, otLinkRawReceiveDone aCallback)
 {
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
     otLogInfoPlat(aInstance, "LinkRaw Recv (Channel %d)", aChannel);
-    return aInstance->mLinkRaw.Receive(aChannel, aCallback);
+    return instance.GetLinkRaw().Receive(aChannel, aCallback);
 }
 
 otRadioFrame *otLinkRawGetTransmitBuffer(otInstance *aInstance)
 {
     otRadioFrame *buffer = NULL;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mLinkRaw.IsEnabled());
+    VerifyOrExit(instance.GetLinkRaw().IsEnabled());
 
     buffer = otPlatRadioGetTransmitBuffer(aInstance);
 
@@ -155,8 +168,10 @@
 
 otError otLinkRawTransmit(otInstance *aInstance, otRadioFrame *aFrame, otLinkRawTransmitDone aCallback)
 {
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
     otLogInfoPlat(aInstance, "LinkRaw Transmit (%d bytes on channel %d)", aFrame->mLength, aFrame->mChannel);
-    return aInstance->mLinkRaw.Transmit(aFrame, aCallback);
+    return instance.GetLinkRaw().Transmit(aFrame, aCallback);
 }
 
 int8_t otLinkRawGetRssi(otInstance *aInstance)
@@ -166,20 +181,25 @@
 
 otRadioCaps otLinkRawGetCaps(otInstance *aInstance)
 {
-    return aInstance->mLinkRaw.GetCaps();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetLinkRaw().GetCaps();
 }
 
 otError otLinkRawEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration,
                             otLinkRawEnergyScanDone aCallback)
 {
-    return aInstance->mLinkRaw.EnergyScan(aScanChannel, aScanDuration, aCallback);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetLinkRaw().EnergyScan(aScanChannel, aScanDuration, aCallback);
 }
 
 otError otLinkRawSrcMatchEnable(otInstance *aInstance, bool aEnable)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 
     otPlatRadioEnableSrcMatch(aInstance, aEnable);
 
@@ -190,8 +210,9 @@
 otError otLinkRawSrcMatchAddShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 
     error = otPlatRadioAddSrcMatchShortEntry(aInstance, aShortAddress);
 
@@ -202,8 +223,9 @@
 otError otLinkRawSrcMatchAddExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 
     error = otPlatRadioAddSrcMatchExtEntry(aInstance, aExtAddress);
 
@@ -214,8 +236,9 @@
 otError otLinkRawSrcMatchClearShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 
     error = otPlatRadioClearSrcMatchShortEntry(aInstance, aShortAddress);
 
@@ -226,8 +249,9 @@
 otError otLinkRawSrcMatchClearExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 
     error = otPlatRadioClearSrcMatchExtEntry(aInstance, aExtAddress);
 
@@ -238,8 +262,9 @@
 otError otLinkRawSrcMatchClearShortEntries(otInstance *aInstance)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 
     otPlatRadioClearSrcMatchShortEntries(aInstance);
 
@@ -250,8 +275,9 @@
 otError otLinkRawSrcMatchClearExtEntries(otInstance *aInstance)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = OT_ERROR_INVALID_STATE);
+    VerifyOrExit(instance.GetLinkRaw().IsEnabled(), error = OT_ERROR_INVALID_STATE);
 
     otPlatRadioClearSrcMatchExtEntries(aInstance);
 
@@ -261,7 +287,7 @@
 
 namespace ot {
 
-LinkRaw::LinkRaw(otInstance &aInstance):
+LinkRaw::LinkRaw(Instance &aInstance):
     mInstance(aInstance),
     mEnabled(false),
     mReceiveChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL),
@@ -607,7 +633,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     LinkRaw &link = *static_cast<LinkRaw *>(aContext.GetContext());
 #else
-    LinkRaw &link = otGetInstance()->mLinkRaw;
+    LinkRaw &link = Instance::Get().GetLinkRaw();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return link;
diff --git a/src/core/api/message_api.cpp b/src/core/api/message_api.cpp
index dda8d7e..258546a 100644
--- a/src/core/api/message_api.cpp
+++ b/src/core/api/message_api.cpp
@@ -35,7 +35,7 @@
 
 #include <openthread/message.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
@@ -46,70 +46,70 @@
 
 uint16_t otMessageGetLength(otMessage *aMessage)
 {
-    Message *message = static_cast<Message *>(aMessage);
-    return message->GetLength();
+    Message &message = *static_cast<Message *>(aMessage);
+    return message.GetLength();
 }
 
 otError otMessageSetLength(otMessage *aMessage, uint16_t aLength)
 {
-    Message *message = static_cast<Message *>(aMessage);
-    return message->SetLength(aLength);
+    Message &message = *static_cast<Message *>(aMessage);
+    return message.SetLength(aLength);
 }
 
 uint16_t otMessageGetOffset(otMessage *aMessage)
 {
-    Message *message = static_cast<Message *>(aMessage);
-    return message->GetOffset();
+    Message &message = *static_cast<Message *>(aMessage);
+    return message.GetOffset();
 }
 
 otError otMessageSetOffset(otMessage *aMessage, uint16_t aOffset)
 {
-    Message *message = static_cast<Message *>(aMessage);
-    return message->SetOffset(aOffset);
+    Message &message = *static_cast<Message *>(aMessage);
+    return message.SetOffset(aOffset);
 }
 
 bool otMessageIsLinkSecurityEnabled(otMessage *aMessage)
 {
-    Message *message = static_cast<Message *>(aMessage);
-    return message->IsLinkSecurityEnabled();
+    Message &message = *static_cast<Message *>(aMessage);
+    return message.IsLinkSecurityEnabled();
 }
 
 void otMessageSetDirectTransmission(otMessage *aMessage, bool aEnabled)
 {
-    Message *message = static_cast<Message *>(aMessage);
+    Message &message = *static_cast<Message *>(aMessage);
 
     if (aEnabled)
     {
-        message->SetDirectTransmission();
+        message.SetDirectTransmission();
     }
     else
     {
-        message->ClearDirectTransmission();
+        message.ClearDirectTransmission();
     }
 }
 
 int8_t otMessageGetRss(otMessage *aMessage)
 {
-    Message *message = static_cast<Message *>(aMessage);
-    return message->GetAverageRss();
+    Message &message = *static_cast<Message *>(aMessage);
+    return message.GetAverageRss();
 }
 
 otError otMessageAppend(otMessage *aMessage, const void *aBuf, uint16_t aLength)
 {
-    Message *message = static_cast<Message *>(aMessage);
-    return message->Append(aBuf, aLength);
+    Message &message = *static_cast<Message *>(aMessage);
+    return message.Append(aBuf, aLength);
 }
 
 int otMessageRead(otMessage *aMessage, uint16_t aOffset, void *aBuf, uint16_t aLength)
 {
-    Message *message = static_cast<Message *>(aMessage);
-    return message->Read(aOffset, aLength, aBuf);
+    Message &message = *static_cast<Message *>(aMessage);
+    return message.Read(aOffset, aLength, aBuf);
 }
 
 int otMessageWrite(otMessage *aMessage, uint16_t aOffset, const void *aBuf, uint16_t aLength)
 {
-    Message *message = static_cast<Message *>(aMessage);
-    return message->Write(aOffset, aLength, aBuf);
+    Message &message = *static_cast<Message *>(aMessage);
+    return message.Write(aOffset, aLength, aBuf);
 }
 
 void otMessageQueueInit(otMessageQueue *aQueue)
@@ -119,40 +119,44 @@
 
 otError otMessageQueueEnqueue(otMessageQueue *aQueue, otMessage *aMessage)
 {
-    Message *message = static_cast<Message *>(aMessage);
-    MessageQueue *queue = static_cast<MessageQueue *>(aQueue);
-    return queue->Enqueue(*message);
+    Message &message = *static_cast<Message *>(aMessage);
+    MessageQueue &queue = *static_cast<MessageQueue *>(aQueue);
+    return queue.Enqueue(message);
 }
 
 otError otMessageQueueEnqueueAtHead(otMessageQueue *aQueue, otMessage *aMessage)
 {
-    Message *message = static_cast<Message *>(aMessage);
-    MessageQueue *queue = static_cast<MessageQueue *>(aQueue);
-    return queue->Enqueue(*message, MessageQueue::kQueuePositionHead);
+    Message &message = *static_cast<Message *>(aMessage);
+    MessageQueue &queue = *static_cast<MessageQueue *>(aQueue);
+    return queue.Enqueue(message, MessageQueue::kQueuePositionHead);
 }
 
 otError otMessageQueueDequeue(otMessageQueue *aQueue, otMessage *aMessage)
 {
-    Message *message = static_cast<Message *>(aMessage);
-    MessageQueue *queue = static_cast<MessageQueue *>(aQueue);
-    return queue->Dequeue(*message);
+    Message &message = *static_cast<Message *>(aMessage);
+    MessageQueue &queue = *static_cast<MessageQueue *>(aQueue);
+    return queue.Dequeue(message);
 }
 
 otMessage *otMessageQueueGetHead(otMessageQueue *aQueue)
 {
-    MessageQueue *queue = static_cast<MessageQueue *>(aQueue);
-    return queue->GetHead();
+    MessageQueue &queue = *static_cast<MessageQueue *>(aQueue);
+    return queue.GetHead();
 }
 
 otMessage *otMessageQueueGetNext(otMessageQueue *aQueue, const otMessage *aMessage)
 {
     Message *next;
-    const Message *message = static_cast<const Message *>(aMessage);
-    MessageQueue *queue = static_cast<MessageQueue *>(aQueue);
 
-    VerifyOrExit(message != NULL, next = NULL);
-    VerifyOrExit(message->GetMessageQueue() == queue, next = NULL);
-    next = message->GetNext();
+    VerifyOrExit(aMessage != NULL, next = NULL);
+
+    {
+        const Message &message = *static_cast<const Message *>(aMessage);
+        MessageQueue &queue = *static_cast<MessageQueue *>(aQueue);
+
+        VerifyOrExit(message.GetMessageQueue() == &queue, next = NULL);
+        next = message.GetNext();
+    }
 
 exit:
     return next;
@@ -161,39 +165,40 @@
 void otMessageGetBufferInfo(otInstance *aInstance, otBufferInfo *aBufferInfo)
 {
     uint16_t messages, buffers;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     aBufferInfo->mTotalBuffers = OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS;
 
-    aBufferInfo->mFreeBuffers = aInstance->mMessagePool.GetFreeBufferCount();
+    aBufferInfo->mFreeBuffers = instance.GetMessagePool().GetFreeBufferCount();
 
-    aInstance->mThreadNetif.GetMeshForwarder().GetSendQueue().GetInfo(aBufferInfo->m6loSendMessages,
-                                                                      aBufferInfo->m6loSendBuffers);
+    instance.GetThreadNetif().GetMeshForwarder().GetSendQueue().GetInfo(aBufferInfo->m6loSendMessages,
+                                                                        aBufferInfo->m6loSendBuffers);
 
-    aInstance->mThreadNetif.GetMeshForwarder().GetReassemblyQueue().GetInfo(aBufferInfo->m6loReassemblyMessages,
-                                                                            aBufferInfo->m6loReassemblyBuffers);
+    instance.GetThreadNetif().GetMeshForwarder().GetReassemblyQueue().GetInfo(aBufferInfo->m6loReassemblyMessages,
+                                                                              aBufferInfo->m6loReassemblyBuffers);
 
-    aInstance->mThreadNetif.GetMeshForwarder().GetResolvingQueue().GetInfo(aBufferInfo->mArpMessages,
-                                                                           aBufferInfo->mArpBuffers);
+    instance.GetThreadNetif().GetMeshForwarder().GetResolvingQueue().GetInfo(aBufferInfo->mArpMessages,
+                                                                             aBufferInfo->mArpBuffers);
 
-    aInstance->mThreadNetif.GetIp6().GetSendQueue().GetInfo(aBufferInfo->mIp6Messages,
-                                                            aBufferInfo->mIp6Buffers);
+    instance.GetThreadNetif().GetIp6().GetSendQueue().GetInfo(aBufferInfo->mIp6Messages,
+                                                              aBufferInfo->mIp6Buffers);
 
-    aInstance->mThreadNetif.GetIp6().GetMpl().GetBufferedMessageSet().GetInfo(aBufferInfo->mMplMessages,
-                                                                              aBufferInfo->mMplBuffers);
+    instance.GetThreadNetif().GetIp6().GetMpl().GetBufferedMessageSet().GetInfo(aBufferInfo->mMplMessages,
+                                                                                aBufferInfo->mMplBuffers);
 
-    aInstance->mThreadNetif.GetMle().GetMessageQueue().GetInfo(aBufferInfo->mMleMessages,
-                                                               aBufferInfo->mMleBuffers);
+    instance.GetThreadNetif().GetMle().GetMessageQueue().GetInfo(aBufferInfo->mMleMessages,
+                                                                 aBufferInfo->mMleBuffers);
 
-    aInstance->mThreadNetif.GetCoap().GetRequestMessages().GetInfo(aBufferInfo->mCoapMessages,
-                                                                   aBufferInfo->mCoapBuffers);
-    aInstance->mThreadNetif.GetCoap().GetCachedResponses().GetInfo(messages, buffers);
+    instance.GetThreadNetif().GetCoap().GetRequestMessages().GetInfo(aBufferInfo->mCoapMessages,
+                                                                     aBufferInfo->mCoapBuffers);
+    instance.GetThreadNetif().GetCoap().GetCachedResponses().GetInfo(messages, buffers);
     aBufferInfo->mCoapMessages += messages;
     aBufferInfo->mCoapBuffers += buffers;
 
 #if OPENTHREAD_ENABLE_DTLS
-    aInstance->mThreadNetif.GetCoapSecure().GetRequestMessages().GetInfo(aBufferInfo->mCoapSecureMessages,
-                                                                         aBufferInfo->mCoapSecureBuffers);
-    aInstance->mThreadNetif.GetCoapSecure().GetCachedResponses().GetInfo(messages, buffers);
+    instance.GetThreadNetif().GetCoapSecure().GetRequestMessages().GetInfo(aBufferInfo->mCoapSecureMessages,
+                                                                           aBufferInfo->mCoapSecureBuffers);
+    instance.GetThreadNetif().GetCoapSecure().GetCachedResponses().GetInfo(messages, buffers);
     aBufferInfo->mCoapSecureMessages += messages;
     aBufferInfo->mCoapSecureBuffers += buffers;
 #else
@@ -202,9 +207,9 @@
 #endif
 
 #if OPENTHREAD_ENABLE_APPLICATION_COAP
-    aInstance->mApplicationCoap.GetRequestMessages().GetInfo(aBufferInfo->mApplicationCoapMessages,
-                                                             aBufferInfo->mApplicationCoapBuffers);
-    aInstance->mApplicationCoap.GetCachedResponses().GetInfo(messages, buffers);
+    instance.GetApplicationCoap().GetRequestMessages().GetInfo(aBufferInfo->mApplicationCoapMessages,
+                                                               aBufferInfo->mApplicationCoapBuffers);
+    instance.GetApplicationCoap().GetCachedResponses().GetInfo(messages, buffers);
     aBufferInfo->mApplicationCoapMessages += messages;
     aBufferInfo->mApplicationCoapBuffers += buffers;
 #else
diff --git a/src/core/api/netdata_api.cpp b/src/core/api/netdata_api.cpp
index e84abc5..febf6f6 100644
--- a/src/core/api/netdata_api.cpp
+++ b/src/core/api/netdata_api.cpp
@@ -35,17 +35,18 @@
 
 #include <openthread/netdata.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
 otError otNetDataGet(otInstance *aInstance, bool aStable, uint8_t *aData, uint8_t *aDataLength)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aData != NULL && aDataLength != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetNetworkDataLeader().GetNetworkData(aStable, aData, *aDataLength);
+    error = instance.GetThreadNetif().GetNetworkDataLeader().GetNetworkData(aStable, aData, *aDataLength);
 
 exit:
     return error;
@@ -55,10 +56,11 @@
                                      otBorderRouterConfig *aConfig)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aIterator && aConfig, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetNetworkDataLeader().GetNextOnMeshPrefix(aIterator, aConfig);
+    error = instance.GetThreadNetif().GetNetworkDataLeader().GetNextOnMeshPrefix(aIterator, aConfig);
 
 exit:
     return error;
@@ -68,10 +70,11 @@
                               otExternalRouteConfig *aConfig)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aIterator && aConfig, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetNetworkDataLeader().GetNextExternalRoute(aIterator, aConfig);
+    error = instance.GetThreadNetif().GetNetworkDataLeader().GetNextExternalRoute(aIterator, aConfig);
 
 exit:
     return error;
@@ -79,10 +82,14 @@
 
 uint8_t otNetDataGetVersion(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetLeaderDataTlv().GetDataVersion();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetLeaderDataTlv().GetDataVersion();
 }
 
 uint8_t otNetDataGetStableVersion(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetLeaderDataTlv().GetStableDataVersion();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetLeaderDataTlv().GetStableDataVersion();
 }
diff --git a/src/core/api/server_api.cpp b/src/core/api/server_api.cpp
index 54f9ade..166d4c6 100644
--- a/src/core/api/server_api.cpp
+++ b/src/core/api/server_api.cpp
@@ -37,17 +37,18 @@
 
 #include <openthread/server.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
 otError otServerGetNetDataLocal(otInstance *aInstance, bool aStable, uint8_t *aData, uint8_t *aDataLength)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aData != NULL && aDataLength != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetNetworkDataLocal().GetNetworkData(aStable, aData, *aDataLength);
+    error = instance.GetThreadNetif().GetNetworkDataLocal().GetNetworkData(aStable, aData, *aDataLength);
 
 exit:
     return error;
@@ -55,7 +56,9 @@
 
 otError otServerAddService(otInstance *aInstance, const otServiceConfig *aConfig)
 {
-    return aInstance->mThreadNetif.GetNetworkDataLocal().AddService(
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetNetworkDataLocal().AddService(
                aConfig->mEnterpriseNumber, &aConfig->mServiceData[0], aConfig->mServiceDataLength,
                aConfig->mServerConfig.mStable, &aConfig->mServerConfig.mServerData[0], aConfig->mServerConfig.mServerDataLength
            );
@@ -64,17 +67,21 @@
 otError otServerRemoveService(otInstance *aInstance, uint32_t aEnterpriseNumber, uint8_t *aServiceData,
                               uint8_t aServiceDataLength)
 {
-    return aInstance->mThreadNetif.GetNetworkDataLocal().RemoveService(aEnterpriseNumber, aServiceData, aServiceDataLength);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetNetworkDataLocal().RemoveService(aEnterpriseNumber, aServiceData,
+                                                                         aServiceDataLength);
 }
 
 otError otServerGetNextService(otInstance *aInstance, otNetworkDataIterator *aIterator,
                                otServiceConfig *aConfig)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aIterator && aConfig, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetNetworkDataLocal().GetNextService(aIterator, aConfig);
+    error = instance.GetThreadNetif().GetNetworkDataLocal().GetNextService(aIterator, aConfig);
 
 exit:
     return error;
@@ -82,7 +89,9 @@
 
 otError otServerRegister(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetNetworkDataLocal().SendServerDataNotification();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetNetworkDataLocal().SendServerDataNotification();
 }
 
 #endif  // OPENTHREAD_ENABLE_SERVICE
diff --git a/src/core/api/tasklet_api.cpp b/src/core/api/tasklet_api.cpp
index 0d88210..69db5ff 100644
--- a/src/core/api/tasklet_api.cpp
+++ b/src/core/api/tasklet_api.cpp
@@ -37,17 +37,19 @@
 
 #include <openthread/tasklet.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 
 using namespace ot;
 
 void otTaskletsProcess(otInstance *aInstance)
 {
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
     otLogFuncEntry();
     VerifyOrExit(otInstanceIsInitialized(aInstance));
-    aInstance->mTaskletScheduler.ProcessQueuedTasklets();
+    instance.GetTaskletScheduler().ProcessQueuedTasklets();
 
 exit:
     otLogFuncExit();
@@ -56,9 +58,10 @@
 bool otTaskletsArePending(otInstance *aInstance)
 {
     bool retval = false;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(otInstanceIsInitialized(aInstance));
-    retval = aInstance->mTaskletScheduler.AreTaskletsPending();
+    retval = instance.GetTaskletScheduler().AreTaskletsPending();
 
 exit:
     return retval;
diff --git a/src/core/api/thread_api.cpp b/src/core/api/thread_api.cpp
index b199eef..c0086f3 100644
--- a/src/core/api/thread_api.cpp
+++ b/src/core/api/thread_api.cpp
@@ -38,7 +38,7 @@
 #include <openthread/thread.h>
 #include <openthread/platform/settings.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/settings.hpp"
 
@@ -46,37 +46,44 @@
 
 uint32_t otThreadGetChildTimeout(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetTimeout();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetTimeout();
 }
 
 void otThreadSetChildTimeout(otInstance *aInstance, uint32_t aTimeout)
 {
-    aInstance->mThreadNetif.GetMle().SetTimeout(aTimeout);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetMle().SetTimeout(aTimeout);
 }
 
 const uint8_t *otThreadGetExtendedPanId(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMac().GetExtendedPanId();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().GetExtendedPanId();
 }
 
 otError otThreadSetExtendedPanId(otInstance *aInstance, const uint8_t *aExtendedPanId)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
     uint8_t mlPrefix[8];
 
-    VerifyOrExit(aInstance->mThreadNetif.GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
+    VerifyOrExit(instance.GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
                  error = OT_ERROR_INVALID_STATE);
 
-    aInstance->mThreadNetif.GetMac().SetExtendedPanId(aExtendedPanId);
+    instance.GetThreadNetif().GetMac().SetExtendedPanId(aExtendedPanId);
 
     mlPrefix[0] = 0xfd;
     memcpy(mlPrefix + 1, aExtendedPanId, 5);
     mlPrefix[6] = 0x00;
     mlPrefix[7] = 0x00;
-    aInstance->mThreadNetif.GetMle().SetMeshLocalPrefix(mlPrefix);
+    instance.GetThreadNetif().GetMle().SetMeshLocalPrefix(mlPrefix);
 
-    aInstance->mThreadNetif.GetActiveDataset().Clear();
-    aInstance->mThreadNetif.GetPendingDataset().Clear();
+    instance.GetThreadNetif().GetActiveDataset().Clear();
+    instance.GetThreadNetif().GetPendingDataset().Clear();
 
 exit:
     return error;
@@ -85,10 +92,11 @@
 otError otThreadGetLeaderRloc(otInstance *aInstance, otIp6Address *aAddress)
 {
     otError error;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aAddress != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetMle().GetLeaderAddress(*static_cast<Ip6::Address *>(aAddress));
+    error = instance.GetThreadNetif().GetMle().GetLeaderAddress(*static_cast<Ip6::Address *>(aAddress));
 
 exit:
     return error;
@@ -97,7 +105,8 @@
 otLinkModeConfig otThreadGetLinkMode(otInstance *aInstance)
 {
     otLinkModeConfig config;
-    uint8_t mode = aInstance->mThreadNetif.GetMle().GetDeviceMode();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+    uint8_t mode = instance.GetThreadNetif().GetMle().GetDeviceMode();
 
     memset(&config, 0, sizeof(otLinkModeConfig));
 
@@ -127,6 +136,7 @@
 otError otThreadSetLinkMode(otInstance *aInstance, otLinkModeConfig aConfig)
 {
     uint8_t mode = 0;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     if (aConfig.mRxOnWhenIdle)
     {
@@ -148,25 +158,28 @@
         mode |= Mle::ModeTlv::kModeFullNetworkData;
     }
 
-    return aInstance->mThreadNetif.GetMle().SetDeviceMode(mode);
+    return instance.GetThreadNetif().GetMle().SetDeviceMode(mode);
 }
 
 const otMasterKey *otThreadGetMasterKey(otInstance *aInstance)
 {
-    return &aInstance->mThreadNetif.GetKeyManager().GetMasterKey();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return &instance.GetThreadNetif().GetKeyManager().GetMasterKey();
 }
 
 otError otThreadSetMasterKey(otInstance *aInstance, const otMasterKey *aKey)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aKey != NULL, error = OT_ERROR_INVALID_ARGS);
-    VerifyOrExit(aInstance->mThreadNetif.GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
+    VerifyOrExit(instance.GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
                  error = OT_ERROR_INVALID_STATE);
 
-    error = aInstance->mThreadNetif.GetKeyManager().SetMasterKey(*aKey);
-    aInstance->mThreadNetif.GetActiveDataset().Clear();
-    aInstance->mThreadNetif.GetPendingDataset().Clear();
+    error = instance.GetThreadNetif().GetKeyManager().SetMasterKey(*aKey);
+    instance.GetThreadNetif().GetActiveDataset().Clear();
+    instance.GetThreadNetif().GetPendingDataset().Clear();
 
 exit:
     return error;
@@ -174,24 +187,29 @@
 
 const otIp6Address *otThreadGetMeshLocalEid(otInstance *aInstance)
 {
-    return &aInstance->mThreadNetif.GetMle().GetMeshLocal64();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return &instance.GetThreadNetif().GetMle().GetMeshLocal64();
 }
 
 const uint8_t *otThreadGetMeshLocalPrefix(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetMeshLocalPrefix();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetMeshLocalPrefix();
 }
 
 otError otThreadSetMeshLocalPrefix(otInstance *aInstance, const uint8_t *aMeshLocalPrefix)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mThreadNetif.GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
+    VerifyOrExit(instance.GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
                  error = OT_ERROR_INVALID_STATE);
 
-    error = aInstance->mThreadNetif.GetMle().SetMeshLocalPrefix(aMeshLocalPrefix);
-    aInstance->mThreadNetif.GetActiveDataset().Clear();
-    aInstance->mThreadNetif.GetPendingDataset().Clear();
+    error = instance.GetThreadNetif().GetMle().SetMeshLocalPrefix(aMeshLocalPrefix);
+    instance.GetThreadNetif().GetActiveDataset().Clear();
+    instance.GetThreadNetif().GetPendingDataset().Clear();
 
 exit:
     return error;
@@ -199,24 +217,29 @@
 
 const otIp6Address *otThreadGetLinkLocalIp6Address(otInstance *aInstance)
 {
-    return &aInstance->mThreadNetif.GetMle().GetLinkLocalAddress();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return &instance.GetThreadNetif().GetMle().GetLinkLocalAddress();
 }
 
 const char *otThreadGetNetworkName(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMac().GetNetworkName();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMac().GetNetworkName();
 }
 
 otError otThreadSetNetworkName(otInstance *aInstance, const char *aNetworkName)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mThreadNetif.GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
+    VerifyOrExit(instance.GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
                  error = OT_ERROR_INVALID_STATE);
 
-    error = aInstance->mThreadNetif.GetMac().SetNetworkName(aNetworkName);
-    aInstance->mThreadNetif.GetActiveDataset().Clear();
-    aInstance->mThreadNetif.GetPendingDataset().Clear();
+    error = instance.GetThreadNetif().GetMac().SetNetworkName(aNetworkName);
+    instance.GetThreadNetif().GetActiveDataset().Clear();
+    instance.GetThreadNetif().GetPendingDataset().Clear();
 
 exit:
     return error;
@@ -224,41 +247,54 @@
 
 uint32_t otThreadGetKeySequenceCounter(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetKeyManager().GetCurrentKeySequence();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetKeyManager().GetCurrentKeySequence();
 }
 
 void otThreadSetKeySequenceCounter(otInstance *aInstance, uint32_t aKeySequenceCounter)
 {
-    aInstance->mThreadNetif.GetKeyManager().SetCurrentKeySequence(aKeySequenceCounter);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetKeyManager().SetCurrentKeySequence(aKeySequenceCounter);
 }
 
 uint32_t otThreadGetKeySwitchGuardTime(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetKeyManager().GetKeySwitchGuardTime();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetKeyManager().GetKeySwitchGuardTime();
 }
 
 void otThreadSetKeySwitchGuardTime(otInstance *aInstance, uint32_t aKeySwitchGuardTime)
 {
-    aInstance->mThreadNetif.GetKeyManager().SetKeySwitchGuardTime(aKeySwitchGuardTime);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetKeyManager().SetKeySwitchGuardTime(aKeySwitchGuardTime);
 }
 
 otError otThreadBecomeDetached(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().BecomeDetached();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().BecomeDetached();
 }
 
 otError otThreadBecomeChild(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().BecomeChild(Mle::kAttachAny);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().BecomeChild(Mle::kAttachAny);
 }
 
 otError otThreadGetNextNeighborInfo(otInstance *aInstance, otNeighborInfoIterator *aIterator, otNeighborInfo *aInfo)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit((aInfo != NULL) && (aIterator != NULL), error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetMle().GetNextNeighborInfo(*aIterator, *aInfo);
+    error = instance.GetThreadNetif().GetMle().GetNextNeighborInfo(*aIterator, *aInfo);
 
 exit:
     return error;
@@ -266,16 +302,19 @@
 
 otDeviceRole otThreadGetDeviceRole(otInstance *aInstance)
 {
-    return static_cast<otDeviceRole>(aInstance->mThreadNetif.GetMle().GetRole());
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return static_cast<otDeviceRole>(instance.GetThreadNetif().GetMle().GetRole());
 }
 
 otError otThreadGetLeaderData(otInstance *aInstance, otLeaderData *aLeaderData)
 {
     otError error;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aLeaderData != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetMle().GetLeaderData(*aLeaderData);
+    error = instance.GetThreadNetif().GetMle().GetLeaderData(*aLeaderData);
 
 exit:
     return error;
@@ -283,32 +322,41 @@
 
 uint8_t otThreadGetLeaderRouterId(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetLeaderDataTlv().GetLeaderRouterId();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetLeaderDataTlv().GetLeaderRouterId();
 }
 
 uint8_t otThreadGetLeaderWeight(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetLeaderDataTlv().GetWeighting();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetLeaderDataTlv().GetWeighting();
 }
 
 uint32_t otThreadGetPartitionId(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetLeaderDataTlv().GetPartitionId();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetLeaderDataTlv().GetPartitionId();
 }
 
 uint16_t otThreadGetRloc16(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetRloc16();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetRloc16();
 }
 
 otError otThreadGetParentInfo(otInstance *aInstance, otRouterInfo *aParentInfo)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
     Router *parent;
 
     VerifyOrExit(aParentInfo != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    parent = aInstance->mThreadNetif.GetMle().GetParent();
+    parent = instance.GetThreadNetif().GetMle().GetParent();
     memcpy(aParentInfo->mExtAddress.m8, &parent->GetExtAddress(), sizeof(aParentInfo->mExtAddress));
 
     aParentInfo->mRloc16          = parent->GetRloc16();
@@ -329,11 +377,12 @@
 otError otThreadGetParentAverageRssi(otInstance *aInstance, int8_t *aParentRssi)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
     Router *parent;
 
     VerifyOrExit(aParentRssi != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    parent = aInstance->mThreadNetif.GetMle().GetParent();
+    parent = instance.GetThreadNetif().GetMle().GetParent();
     *aParentRssi = parent->GetLinkInfo().GetAverageRss();
 
     VerifyOrExit(*aParentRssi != OT_RADIO_RSSI_INVALID, error = OT_ERROR_FAILED);
@@ -345,11 +394,12 @@
 otError otThreadGetParentLastRssi(otInstance *aInstance, int8_t *aLastRssi)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
     Router *parent;
 
     VerifyOrExit(aLastRssi != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    parent = aInstance->mThreadNetif.GetMle().GetParent();
+    parent = instance.GetThreadNetif().GetMle().GetParent();
     *aLastRssi = parent->GetLinkInfo().GetLastRss();
 
     VerifyOrExit(*aLastRssi != OT_RADIO_RSSI_INVALID, error = OT_ERROR_FAILED);
@@ -398,43 +448,50 @@
 void otThreadSetReceiveDiagnosticGetCallback(otInstance *aInstance, otReceiveDiagnosticGetCallback aCallback,
                                              void *aCallbackContext)
 {
-    aInstance->mThreadNetif.GetNetworkDiagnostic().SetReceiveDiagnosticGetCallback(aCallback, aCallbackContext);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetNetworkDiagnostic().SetReceiveDiagnosticGetCallback(aCallback, aCallbackContext);
 }
 
 otError otThreadSendDiagnosticGet(otInstance *aInstance, const otIp6Address *aDestination,
                                   const uint8_t aTlvTypes[], uint8_t aCount)
 {
-    return aInstance->mThreadNetif.GetNetworkDiagnostic().SendDiagnosticGet(*static_cast<const Ip6::Address *>
-                                                                            (aDestination),
-                                                                            aTlvTypes,
-                                                                            aCount);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetNetworkDiagnostic().SendDiagnosticGet(*static_cast<const Ip6::Address *>
+                                                                              (aDestination),
+                                                                              aTlvTypes,
+                                                                              aCount);
 }
 
 otError otThreadSendDiagnosticReset(otInstance *aInstance, const otIp6Address *aDestination,
                                     const uint8_t aTlvTypes[], uint8_t aCount)
 {
-    return aInstance->mThreadNetif.GetNetworkDiagnostic().SendDiagnosticReset(*static_cast<const Ip6::Address *>
-                                                                              (aDestination),
-                                                                              aTlvTypes,
-                                                                              aCount);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetNetworkDiagnostic().SendDiagnosticReset(*static_cast<const Ip6::Address *>
+                                                                                (aDestination),
+                                                                                aTlvTypes,
+                                                                                aCount);
 }
 #endif // OPENTHREAD_FTD || OPENTHREAD_ENABLE_MTD_NETWORK_DIAGNOSTIC
 
 otError otThreadSetEnabled(otInstance *aInstance, bool aEnabled)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     otLogFuncEntry();
 
     if (aEnabled)
     {
-        VerifyOrExit(aInstance->mThreadNetif.GetMac().GetPanId() != Mac::kPanIdBroadcast,
+        VerifyOrExit(instance.GetThreadNetif().GetMac().GetPanId() != Mac::kPanIdBroadcast,
                      error = OT_ERROR_INVALID_STATE);
-        error = aInstance->mThreadNetif.GetMle().Start(true, false);
+        error = instance.GetThreadNetif().GetMle().Start(true, false);
     }
     else
     {
-        error = aInstance->mThreadNetif.GetMle().Stop(true);
+        error = instance.GetThreadNetif().GetMle().Stop(true);
     }
 
 exit:
@@ -475,22 +532,30 @@
 
 bool otThreadIsSingleton(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().IsSingleton();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().IsSingleton();
 }
 
 otError otThreadDiscover(otInstance *aInstance, uint32_t aScanChannels, uint16_t aPanId, bool aJoiner,
                          bool aEnableEui64Filtering, otHandleActiveScanResult aCallback, void *aCallbackContext)
 {
-    return aInstance->mThreadNetif.GetMle().Discover(aScanChannels, aPanId, aJoiner, aEnableEui64Filtering, aCallback,
-                                                     aCallbackContext);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().Discover(aScanChannels, aPanId, aJoiner, aEnableEui64Filtering, aCallback,
+                                                       aCallbackContext);
 }
 
 bool otThreadIsDiscoverInProgress(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().IsDiscoverInProgress();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().IsDiscoverInProgress();
 }
 
 const otIpCounters *otThreadGetIp6Counters(otInstance *aInstance)
 {
-    return &aInstance->mThreadNetif.GetMeshForwarder().GetCounters();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return &instance.GetThreadNetif().GetMeshForwarder().GetCounters();
 }
diff --git a/src/core/api/thread_ftd_api.cpp b/src/core/api/thread_ftd_api.cpp
index 761a00b..415dcfa 100644
--- a/src/core/api/thread_ftd_api.cpp
+++ b/src/core/api/thread_ftd_api.cpp
@@ -38,7 +38,8 @@
 #if OPENTHREAD_FTD
 
 #include <openthread/thread_ftd.h>
-#include "openthread-instance.h"
+
+#include "common/instance.hpp"
 #include "thread/mle_constants.hpp"
 
 using namespace ot;
@@ -46,109 +47,145 @@
 uint8_t otThreadGetMaxAllowedChildren(otInstance *aInstance)
 {
     uint8_t aNumChildren;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    (void)aInstance->mThreadNetif.GetMle().GetChildren(&aNumChildren);
+    (void)instance.GetThreadNetif().GetMle().GetChildren(&aNumChildren);
 
     return aNumChildren;
 }
 
 otError otThreadSetMaxAllowedChildren(otInstance *aInstance, uint8_t aMaxChildren)
 {
-    return aInstance->mThreadNetif.GetMle().SetMaxAllowedChildren(aMaxChildren);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().SetMaxAllowedChildren(aMaxChildren);
 }
 
 bool otThreadIsRouterRoleEnabled(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().IsRouterRoleEnabled();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().IsRouterRoleEnabled();
 }
 
 void otThreadSetRouterRoleEnabled(otInstance *aInstance, bool aEnabled)
 {
-    aInstance->mThreadNetif.GetMle().SetRouterRoleEnabled(aEnabled);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetMle().SetRouterRoleEnabled(aEnabled);
 }
 
 otError otThreadSetPreferredRouterId(otInstance *aInstance, uint8_t aRouterId)
 {
-    return aInstance->mThreadNetif.GetMle().SetPreferredRouterId(aRouterId);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().SetPreferredRouterId(aRouterId);
 }
 
 uint8_t otThreadGetLocalLeaderWeight(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetLeaderWeight();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetLeaderWeight();
 }
 
 void otThreadSetLocalLeaderWeight(otInstance *aInstance, uint8_t aWeight)
 {
-    aInstance->mThreadNetif.GetMle().SetLeaderWeight(aWeight);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetMle().SetLeaderWeight(aWeight);
 }
 
 uint32_t otThreadGetLocalLeaderPartitionId(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetLeaderPartitionId();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetLeaderPartitionId();
 }
 
 void otThreadSetLocalLeaderPartitionId(otInstance *aInstance, uint32_t aPartitionId)
 {
-    return aInstance->mThreadNetif.GetMle().SetLeaderPartitionId(aPartitionId);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().SetLeaderPartitionId(aPartitionId);
 }
 
 uint16_t otThreadGetJoinerUdpPort(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetJoinerRouter().GetJoinerUdpPort();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetJoinerRouter().GetJoinerUdpPort();
 }
 
 otError otThreadSetJoinerUdpPort(otInstance *aInstance, uint16_t aJoinerUdpPort)
 {
-    return aInstance->mThreadNetif.GetJoinerRouter().SetJoinerUdpPort(aJoinerUdpPort);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetJoinerRouter().SetJoinerUdpPort(aJoinerUdpPort);
 }
 
 uint32_t otThreadGetContextIdReuseDelay(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetNetworkDataLeader().GetContextIdReuseDelay();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetNetworkDataLeader().GetContextIdReuseDelay();
 }
 
 void otThreadSetContextIdReuseDelay(otInstance *aInstance, uint32_t aDelay)
 {
-    aInstance->mThreadNetif.GetNetworkDataLeader().SetContextIdReuseDelay(aDelay);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetNetworkDataLeader().SetContextIdReuseDelay(aDelay);
 }
 
 uint8_t otThreadGetNetworkIdTimeout(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetNetworkIdTimeout();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetNetworkIdTimeout();
 }
 
 void otThreadSetNetworkIdTimeout(otInstance *aInstance, uint8_t aTimeout)
 {
-    aInstance->mThreadNetif.GetMle().SetNetworkIdTimeout((uint8_t)aTimeout);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetMle().SetNetworkIdTimeout((uint8_t)aTimeout);
 }
 
 uint8_t otThreadGetRouterUpgradeThreshold(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetRouterUpgradeThreshold();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetRouterUpgradeThreshold();
 }
 
 void otThreadSetRouterUpgradeThreshold(otInstance *aInstance, uint8_t aThreshold)
 {
-    aInstance->mThreadNetif.GetMle().SetRouterUpgradeThreshold(aThreshold);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetMle().SetRouterUpgradeThreshold(aThreshold);
 }
 
 otError otThreadReleaseRouterId(otInstance *aInstance, uint8_t aRouterId)
 {
-    return aInstance->mThreadNetif.GetMle().ReleaseRouterId(aRouterId);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().ReleaseRouterId(aRouterId);
 }
 
 otError otThreadBecomeRouter(otInstance *aInstance)
 {
     otError error = OT_ERROR_INVALID_STATE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    switch (aInstance->mThreadNetif.GetMle().GetRole())
+    switch (instance.GetThreadNetif().GetMle().GetRole())
     {
     case OT_DEVICE_ROLE_DISABLED:
     case OT_DEVICE_ROLE_DETACHED:
         break;
 
     case OT_DEVICE_ROLE_CHILD:
-        error = aInstance->mThreadNetif.GetMle().BecomeRouter(ThreadStatusTlv::kHaveChildIdRequest);
+        error = instance.GetThreadNetif().GetMle().BecomeRouter(ThreadStatusTlv::kHaveChildIdRequest);
         break;
 
     case OT_DEVICE_ROLE_ROUTER:
@@ -162,36 +199,47 @@
 
 otError otThreadBecomeLeader(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().BecomeLeader();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().BecomeLeader();
 }
 
 uint8_t otThreadGetRouterDowngradeThreshold(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetRouterDowngradeThreshold();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetRouterDowngradeThreshold();
 }
 
 void otThreadSetRouterDowngradeThreshold(otInstance *aInstance, uint8_t aThreshold)
 {
-    aInstance->mThreadNetif.GetMle().SetRouterDowngradeThreshold(aThreshold);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetMle().SetRouterDowngradeThreshold(aThreshold);
 }
 
 uint8_t otThreadGetRouterSelectionJitter(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetRouterSelectionJitter();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetRouterSelectionJitter();
 }
 
 void otThreadSetRouterSelectionJitter(otInstance *aInstance, uint8_t aRouterJitter)
 {
-    aInstance->mThreadNetif.GetMle().SetRouterSelectionJitter(aRouterJitter);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetMle().SetRouterSelectionJitter(aRouterJitter);
 }
 
 otError otThreadGetChildInfoById(otInstance *aInstance, uint16_t aChildId, otChildInfo *aChildInfo)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aChildInfo != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetMle().GetChildInfoById(aChildId, *aChildInfo);
+    error = instance.GetThreadNetif().GetMle().GetChildInfoById(aChildId, *aChildInfo);
 
 exit:
     return error;
@@ -200,10 +248,11 @@
 otError otThreadGetChildInfoByIndex(otInstance *aInstance, uint8_t aChildIndex, otChildInfo *aChildInfo)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aChildInfo != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetMle().GetChildInfoByIndex(aChildIndex, *aChildInfo);
+    error = instance.GetThreadNetif().GetMle().GetChildInfoByIndex(aChildIndex, *aChildInfo);
 
 exit:
     return error;
@@ -211,7 +260,9 @@
 
 uint8_t otThreadGetRouterIdSequence(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetRouterIdSequence();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetRouterIdSequence();
 }
 
 uint8_t otThreadGetMaxRouterId(otInstance *aInstance)
@@ -223,10 +274,11 @@
 otError otThreadGetRouterInfo(otInstance *aInstance, uint16_t aRouterId, otRouterInfo *aRouterInfo)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aRouterInfo != NULL, error = OT_ERROR_INVALID_ARGS);
 
-    error = aInstance->mThreadNetif.GetMle().GetRouterInfo(aRouterId, *aRouterInfo);
+    error = instance.GetThreadNetif().GetMle().GetRouterInfo(aRouterId, *aRouterInfo);
 
 exit:
     return error;
@@ -235,9 +287,10 @@
 otError otThreadGetEidCacheEntry(otInstance *aInstance, uint8_t aIndex, otEidCacheEntry *aEntry)
 {
     otError error;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
     VerifyOrExit(aEntry != NULL, error = OT_ERROR_INVALID_ARGS);
-    error = aInstance->mThreadNetif.GetAddressResolver().GetEntry(aIndex, *aEntry);
+    error = instance.GetThreadNetif().GetAddressResolver().GetEntry(aIndex, *aEntry);
 
 exit:
     return error;
@@ -248,32 +301,37 @@
     otError error;
 
 #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
-    error = aInstance->mThreadNetif.GetMle().SetSteeringData(aExtAddress);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    error = instance.GetThreadNetif().GetMle().SetSteeringData(aExtAddress);
 #else
     OT_UNUSED_VARIABLE(aInstance);
     OT_UNUSED_VARIABLE(aExtAddress);
 
     error = OT_ERROR_DISABLED_FEATURE;
-#endif  // OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
+#endif
 
     return error;
 }
 
 const uint8_t *otThreadGetPSKc(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetKeyManager().GetPSKc();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetKeyManager().GetPSKc();
 }
 
 otError otThreadSetPSKc(otInstance *aInstance, const uint8_t *aPSKc)
 {
     otError error = OT_ERROR_NONE;
+    Instance &instance = *static_cast<Instance *>(aInstance);
 
-    VerifyOrExit(aInstance->mThreadNetif.GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
+    VerifyOrExit(instance.GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
                  error = OT_ERROR_INVALID_STATE);
 
-    aInstance->mThreadNetif.GetKeyManager().SetPSKc(aPSKc);
-    aInstance->mThreadNetif.GetActiveDataset().Clear();
-    aInstance->mThreadNetif.GetPendingDataset().Clear();
+    instance.GetThreadNetif().GetKeyManager().SetPSKc(aPSKc);
+    instance.GetThreadNetif().GetActiveDataset().Clear();
+    instance.GetThreadNetif().GetPendingDataset().Clear();
 
 exit:
     return error;
@@ -281,22 +339,30 @@
 
 int8_t otThreadGetParentPriority(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetAssignParentPriority();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetAssignParentPriority();
 }
 
 otError otThreadSetParentPriority(otInstance *aInstance, const int8_t aParentPriority)
 {
-    return aInstance->mThreadNetif.GetMle().SetAssignParentPriority(aParentPriority);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().SetAssignParentPriority(aParentPriority);
 }
 
 otThreadChildTableCallback otThreadGetChildTableCallback(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetMle().GetChildTableChangedCallback();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetMle().GetChildTableChangedCallback();
 }
 
 void otThreadSetChildTableCallback(otInstance *aInstance, otThreadChildTableCallback aCallback)
 {
-    aInstance->mThreadNetif.GetMle().SetChildTableChangedCallback(aCallback);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    instance.GetThreadNetif().GetMle().SetChildTableChangedCallback(aCallback);
 }
 
 #endif // OPENTHREAD_FTD
diff --git a/src/core/api/tmf_proxy_api.cpp b/src/core/api/tmf_proxy_api.cpp
index 7f2a0ab..fa90631 100644
--- a/src/core/api/tmf_proxy_api.cpp
+++ b/src/core/api/tmf_proxy_api.cpp
@@ -35,28 +35,38 @@
 
 #include <openthread/tmf_proxy.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY
 
+using namespace ot;
+
 otError otTmfProxyStart(otInstance *aInstance, otTmfProxyStreamHandler aTmfProxyCallback, void *aContext)
 {
-    return aInstance->mThreadNetif.GetTmfProxy().Start(aTmfProxyCallback, aContext);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetTmfProxy().Start(aTmfProxyCallback, aContext);
 }
 
 otError otTmfProxyStop(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetTmfProxy().Stop();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetTmfProxy().Stop();
 }
 
 otError otTmfProxySend(otInstance *aInstance, otMessage *aMessage, uint16_t aLocator, uint16_t aPort)
 {
-    return aInstance->mThreadNetif.GetTmfProxy().Send(*static_cast<ot::Message *>(aMessage), aLocator, aPort);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetTmfProxy().Send(*static_cast<ot::Message *>(aMessage), aLocator, aPort);
 }
 
 bool otTmfProxyIsEnabled(otInstance *aInstance)
 {
-    return aInstance->mThreadNetif.GetTmfProxy().IsEnabled();
+    Instance &instance = *static_cast<Instance *>(aInstance);
+
+    return instance.GetThreadNetif().GetTmfProxy().IsEnabled();
 }
 
 #endif // OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY
diff --git a/src/core/api/udp_api.cpp b/src/core/api/udp_api.cpp
index 90db4f3..00e7b7d 100644
--- a/src/core/api/udp_api.cpp
+++ b/src/core/api/udp_api.cpp
@@ -35,13 +35,14 @@
 
 #include <openthread/udp.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 
 using namespace ot;
 
 otMessage *otUdpNewMessage(otInstance *aInstance, bool aLinkSecurityEnabled)
 {
-    Message *message = aInstance->mIp6.GetUdp().NewMessage(0);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+    Message *message = instance.GetIp6().GetUdp().NewMessage(0);
 
     if (message)
     {
@@ -54,12 +55,13 @@
 otError otUdpOpen(otInstance *aInstance, otUdpSocket *aSocket, otUdpReceive aCallback, void *aCallbackContext)
 {
     otError error = OT_ERROR_INVALID_ARGS;
-    Ip6::UdpSocket *socket = static_cast<Ip6::UdpSocket *>(aSocket);
+    Instance &instance = *static_cast<Instance *>(aInstance);
+    Ip6::UdpSocket &socket = *static_cast<Ip6::UdpSocket *>(aSocket);
 
-    if (socket->mTransport == NULL)
+    if (socket.mTransport == NULL)
     {
-        socket->mTransport = &aInstance->mIp6.GetUdp();
-        error = socket->Open(aCallback, aCallbackContext);
+        socket.mTransport = &instance.GetIp6().GetUdp();
+        error = socket.Open(aCallback, aCallbackContext);
     }
 
     return error;
@@ -68,15 +70,15 @@
 otError otUdpClose(otUdpSocket *aSocket)
 {
     otError error = OT_ERROR_INVALID_STATE;
-    Ip6::UdpSocket *socket = static_cast<Ip6::UdpSocket *>(aSocket);
+    Ip6::UdpSocket &socket = *static_cast<Ip6::UdpSocket *>(aSocket);
 
-    if (socket->mTransport != NULL)
+    if (socket.mTransport != NULL)
     {
-        error = socket->Close();
+        error = socket.Close();
 
         if (error == OT_ERROR_NONE)
         {
-            socket->mTransport = NULL;
+            socket.mTransport = NULL;
         }
     }
 
@@ -85,19 +87,19 @@
 
 otError otUdpBind(otUdpSocket *aSocket, otSockAddr *aSockName)
 {
-    Ip6::UdpSocket *socket = static_cast<Ip6::UdpSocket *>(aSocket);
-    return socket->Bind(*static_cast<const Ip6::SockAddr *>(aSockName));
+    Ip6::UdpSocket &socket = *static_cast<Ip6::UdpSocket *>(aSocket);
+    return socket.Bind(*static_cast<const Ip6::SockAddr *>(aSockName));
 }
 
 otError otUdpConnect(otUdpSocket *aSocket, otSockAddr *aSockName)
 {
-    Ip6::UdpSocket *socket = static_cast<Ip6::UdpSocket *>(aSocket);
-    return socket->Connect(*static_cast<const Ip6::SockAddr *>(aSockName));
+    Ip6::UdpSocket &socket = *static_cast<Ip6::UdpSocket *>(aSocket);
+    return socket.Connect(*static_cast<const Ip6::SockAddr *>(aSockName));
 }
 
 otError otUdpSend(otUdpSocket *aSocket, otMessage *aMessage, const otMessageInfo *aMessageInfo)
 {
-    Ip6::UdpSocket *socket = static_cast<Ip6::UdpSocket *>(aSocket);
-    return socket->SendTo(*static_cast<Message *>(aMessage),
-                          *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
+    Ip6::UdpSocket &socket = *static_cast<Ip6::UdpSocket *>(aSocket);
+    return socket.SendTo(*static_cast<Message *>(aMessage),
+                         *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
 }
diff --git a/src/core/coap/coap.cpp b/src/core/coap/coap.cpp
index 9bd7e1d..e402c74 100644
--- a/src/core/coap/coap.cpp
+++ b/src/core/coap/coap.cpp
@@ -32,9 +32,9 @@
 
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "net/ip6.hpp"
 #include "net/udp6.hpp"
@@ -48,10 +48,10 @@
 namespace ot {
 namespace Coap {
 
-CoapBase::CoapBase(otInstance &aInstance, Timer::Handler aRetransmissionTimerHandler,
+CoapBase::CoapBase(Instance &aInstance, Timer::Handler aRetransmissionTimerHandler,
                    Timer::Handler aResponsesQueueTimerHandler):
     InstanceLocator(aInstance),
-    mSocket(aInstance.mThreadNetif.GetIp6().GetUdp()),
+    mSocket(aInstance.GetThreadNetif().GetIp6().GetUdp()),
     mRetransmissionTimer(aInstance, aRetransmissionTimerHandler, this),
     mResources(NULL),
     mContext(NULL),
@@ -744,7 +744,7 @@
     mConfirmable = aConfirmable;
 }
 
-ResponsesQueue::ResponsesQueue(otInstance &aInstance, Timer::Handler aHandler, void *aContext):
+ResponsesQueue::ResponsesQueue(Instance &aInstance, Timer::Handler aHandler, void *aContext):
     mQueue(),
     mTimer(aInstance, aHandler, aContext)
 {
@@ -911,7 +911,7 @@
     return remainingTime >= 0 ? static_cast<uint32_t>(remainingTime) : 0;
 }
 
-Coap::Coap(otInstance &aInstance):
+Coap::Coap(Instance &aInstance):
     CoapBase(aInstance, &Coap::HandleRetransmissionTimer, &Coap::HandleResponsesQueueTimer)
 {
 }
@@ -921,7 +921,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     Coap &coap = *static_cast<Coap *>(aContext.GetContext());
 #else
-    Coap &coap = otGetThreadNetif().GetCoap();
+    Coap &coap = Instance::Get().GetThreadNetif().GetCoap();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return coap;
@@ -939,7 +939,7 @@
 
 #if OPENTHREAD_ENABLE_APPLICATION_COAP
 
-ApplicationCoap::ApplicationCoap(otInstance &aInstance):
+ApplicationCoap::ApplicationCoap(Instance &aInstance):
     CoapBase(aInstance, &ApplicationCoap::HandleRetransmissionTimer, &ApplicationCoap::HandleResponsesQueueTimer)
 {
 }
@@ -949,7 +949,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     ApplicationCoap &coap = *static_cast<ApplicationCoap *>(aContext.GetContext());
 #else
-    ApplicationCoap &coap = otGetInstance()->mApplicationCoap;
+    ApplicationCoap &coap = Instance::Get().GetApplicationCoap();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return coap;
diff --git a/src/core/coap/coap.hpp b/src/core/coap/coap.hpp
index 3cfddba..0cb6f21 100644
--- a/src/core/coap/coap.hpp
+++ b/src/core/coap/coap.hpp
@@ -337,7 +337,7 @@
      * @param[in]  aContext   A pointer to arbitrary context information (used along with timer handler).
      *
      */
-    ResponsesQueue(otInstance &aInstance, Timer::Handler aHandler, void *aContext);
+    ResponsesQueue(Instance &aInstance, Timer::Handler aHandler, void *aContext);
 
     /**
      * Add given response to the cache.
@@ -656,7 +656,7 @@
      * @param[in]  aResponsesQueueTimerHandler    A timer handler provided by sub-class for `mReponsesQueue` timer.
      *
      */
-    CoapBase(otInstance &aInstance, Timer::Handler aRetransmissionTimerHandler,
+    CoapBase(Instance &aInstance, Timer::Handler aRetransmissionTimerHandler,
              Timer::Handler aResponsesQueueTimerHandler);
 
     /**
@@ -747,7 +747,7 @@
      * @param[in] aInstance      A reference to the OpenThread instance.
      *
      */
-    Coap(otInstance &aInstance);
+    Coap(Instance &aInstance);
 
 private:
     static Coap &GetOwner(const Context &aContext);
@@ -770,7 +770,7 @@
      * @param[in] aInstance      A reference to the OpenThread instance.
      *
      */
-    ApplicationCoap(otInstance &aInstance);
+    ApplicationCoap(Instance &aInstance);
 
 private:
     static ApplicationCoap &GetOwner(const Context &aContext);
diff --git a/src/core/coap/coap_header.cpp b/src/core/coap/coap_header.cpp
index 8acb585..90071cb 100644
--- a/src/core/coap/coap_header.cpp
+++ b/src/core/coap/coap_header.cpp
@@ -39,6 +39,7 @@
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 
 namespace ot {
 namespace Coap {
diff --git a/src/core/coap/coap_secure.cpp b/src/core/coap/coap_secure.cpp
index 5404b70..385874e 100644
--- a/src/core/coap/coap_secure.cpp
+++ b/src/core/coap/coap_secure.cpp
@@ -30,9 +30,9 @@
 
 #include "coap_secure.hpp"
 
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "meshcop/dtls.hpp"
-#include "openthread-instance.h"
 #include "thread/thread_netif.hpp"
 
 #if OPENTHREAD_ENABLE_DTLS
@@ -45,7 +45,7 @@
 namespace ot {
 namespace Coap {
 
-CoapSecure::CoapSecure(otInstance &aInstance):
+CoapSecure::CoapSecure(Instance &aInstance):
     CoapBase(aInstance, &CoapSecure::HandleRetransmissionTimer, &CoapSecure::HandleResponsesQueueTimer),
     mConnectedCallback(NULL),
     mConnectedContext(NULL),
@@ -219,7 +219,7 @@
 
     otLogFuncEntry();
 
-    VerifyOrExit((message = GetInstance().mMessagePool.New(Message::kTypeIp6, 0)) != NULL);
+    VerifyOrExit((message = GetInstance().GetMessagePool().New(Message::kTypeIp6, 0)) != NULL);
     SuccessOrExit(message->Append(aBuf, aLength));
 
     CoapBase::Receive(*message, mPeerAddress);
@@ -314,7 +314,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     CoapSecure &coap = *static_cast<CoapSecure *>(aContext.GetContext());
 #else
-    CoapSecure &coap = otGetThreadNetif().GetCoapSecure();
+    CoapSecure &coap = Instance::Get().GetThreadNetif().GetCoapSecure();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return coap;
diff --git a/src/core/coap/coap_secure.hpp b/src/core/coap/coap_secure.hpp
index 0f897b6..b4ed391 100644
--- a/src/core/coap/coap_secure.hpp
+++ b/src/core/coap/coap_secure.hpp
@@ -73,7 +73,7 @@
      * @param[in]  aInstance  A reference to the OpenThread instance.
      *
      */
-    CoapSecure(otInstance &aInstance);
+    CoapSecure(Instance &aInstance);
 
     /**
      * This method starts the secure CoAP agent.
diff --git a/src/core/common/instance.cpp b/src/core/common/instance.cpp
new file mode 100644
index 0000000..14e1d96
--- /dev/null
+++ b/src/core/common/instance.cpp
@@ -0,0 +1,242 @@
+/*
+ *  Copyright (c) 2016-2017, The OpenThread Authors.
+ *  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 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 the copyright holder nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ */
+
+/**
+ * @file
+ *   This file implements the OpenThread Instance class.
+ */
+
+#define WPP_NAME "instance.tmh"
+
+#include "instance.hpp"
+
+#include <openthread/platform/misc.h>
+#include <openthread/platform/settings.h>
+
+#include "common/logging.hpp"
+#include "common/new.hpp"
+
+namespace ot {
+
+#if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
+
+// Define the raw storage used for OpenThread instance (in single-instance case).
+static otDEFINE_ALIGNED_VAR(sInstanceRaw, sizeof(Instance), uint64_t);
+
+#endif
+
+Instance::Instance(void) :
+    mActiveScanCallback(NULL),
+    mActiveScanCallbackContext(NULL),
+    mEnergyScanCallback(NULL),
+    mEnergyScanCallbackContext(NULL),
+    mTimerMilliScheduler(*this),
+#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
+    mTimerMicroScheduler(*this),
+#endif
+    mIp6(*this),
+    mThreadNetif(*this),
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+    mLinkRaw(*this),
+#endif
+#if OPENTHREAD_ENABLE_APPLICATION_COAP
+    mApplicationCoap(*this),
+#endif
+#if OPENTHREAD_CONFIG_ENABLE_DYNAMIC_LOG_LEVEL
+    mLogLevel(static_cast<otLogLevel>(OPENTHREAD_CONFIG_LOG_LEVEL)),
+#endif
+    mMessagePool(*this),
+    mIsInitialized(false)
+{
+}
+
+#if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
+
+Instance &Instance::InitSingle(void)
+{
+    Instance *instance = &Get();
+
+    VerifyOrExit(instance->mIsInitialized == false);
+
+    instance = new(&sInstanceRaw)Instance();
+
+    instance->AfterInit();
+
+exit:
+    return *instance;
+}
+
+Instance &Instance::Get(void)
+{
+    return *reinterpret_cast<Instance *>(&sInstanceRaw);
+}
+
+#else // #if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
+
+Instance *Instance::Init(void *aBuffer, size_t *aBufferSize)
+{
+    Instance *instance = NULL;
+
+    VerifyOrExit(aBufferSize != NULL);
+
+    // Make sure the input buffer is big enough
+    VerifyOrExit(sizeof(Instance) <= *aBufferSize, *aBufferSize = sizeof(Instance));
+
+    VerifyOrExit(aBuffer != NULL);
+
+    instance = new(aBuffer)Instance();
+
+    instance->AfterInit();
+
+exit:
+    return instance;
+}
+
+#endif // OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
+
+void Instance::AfterInit(void)
+{
+    mIsInitialized = true;
+
+    // Restore datasets and network information
+
+    otPlatSettingsInit(this);
+    mThreadNetif.GetMle().Restore();
+
+#if OPENTHREAD_CONFIG_ENABLE_AUTO_START_SUPPORT
+
+    if (otThreadGetAutoStart(this))
+    {
+        if (otIp6SetEnabled(this, true) == OT_ERROR_NONE)
+        {
+            // Only try to start Thread if we could bring up the interface
+            if (otThreadSetEnabled(this, true) != OT_ERROR_NONE)
+            {
+                // Bring the interface down if Thread failed to start
+                otIp6SetEnabled(this, false);
+            }
+        }
+    }
+
+#endif
+}
+
+void Instance::Finalize(void)
+{
+    VerifyOrExit(mIsInitialized == true);
+
+    mIsInitialized = false;
+
+    IgnoreReturnValue(otThreadSetEnabled(this, false));
+    IgnoreReturnValue(otIp6SetEnabled(this, false));
+
+exit:
+    return;
+}
+
+otError Instance::RegisterStateChangedCallback(otStateChangedCallback aCallback, void *aContext)
+{
+    otError error = OT_ERROR_NO_BUFS;
+
+    for (size_t i = 0; i < kMaxNetifCallbacks; i++)
+    {
+        if (mNetifCallback[i].IsFree())
+        {
+            mNetifCallback[i].Set(aCallback, aContext);
+            error = mThreadNetif.RegisterCallback(mNetifCallback[i]);
+            break;
+        }
+    }
+
+    return error;
+}
+
+void Instance::RemoveStateChangedCallback(otStateChangedCallback aCallback, void *aContext)
+{
+    for (size_t i = 0; i < kMaxNetifCallbacks; i++)
+    {
+        if (mNetifCallback[i].IsServing(aCallback, aContext))
+        {
+            mThreadNetif.RemoveCallback(mNetifCallback[i]);
+            mNetifCallback[i].Free();
+            break;
+        }
+    }
+}
+
+void Instance::Reset(void)
+{
+    otPlatReset(this);
+}
+
+void Instance::FactoryReset(void)
+{
+    otPlatSettingsWipe(this);
+    otPlatReset(this);
+}
+
+otError Instance::ErasePersistentInfo(void)
+{
+    otError error = OT_ERROR_NONE;
+
+    VerifyOrExit(mThreadNetif.GetMle().GetRole() ==  OT_DEVICE_ROLE_DISABLED, error = OT_ERROR_INVALID_STATE);
+    otPlatSettingsWipe(this);
+
+exit:
+    return error;
+}
+
+void Instance::RegisterActiveScanCallback(otHandleActiveScanResult aCallback, void *aContext)
+{
+    mActiveScanCallback = aCallback;
+    mActiveScanCallbackContext = aContext;
+}
+
+void Instance::InvokeActiveScanCallback(otActiveScanResult *aResult) const
+{
+    if (mActiveScanCallback != NULL)
+    {
+        mActiveScanCallback(aResult, mActiveScanCallbackContext);
+    }
+}
+
+void Instance::RegisterEnergyScanCallback(otHandleEnergyScanResult aCallback, void *aContext)
+{
+    mEnergyScanCallback = aCallback;
+    mEnergyScanCallbackContext = aContext;
+}
+
+void Instance::InvokeEnergyScanCallback(otEnergyScanResult *aResult) const
+{
+    if (mEnergyScanCallback != NULL)
+    {
+        mEnergyScanCallback(aResult, mEnergyScanCallbackContext);
+    }
+}
+
+} // namespance ot
\ No newline at end of file
diff --git a/src/core/common/instance.hpp b/src/core/common/instance.hpp
new file mode 100644
index 0000000..29dc9d5
--- /dev/null
+++ b/src/core/common/instance.hpp
@@ -0,0 +1,377 @@
+/*
+ *  Copyright (c) 2016-2017, The OpenThread Authors.
+ *  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 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 the copyright holder nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ */
+
+/**
+ * @file
+ *  This file defines OpenThread instance class.
+ */
+
+#ifndef INSTANCE_HPP_
+#define INSTANCE_HPP_
+
+#include "openthread-core-config.h"
+
+#include "utils/wrap_stdint.h"
+#include "utils/wrap_stdbool.h"
+
+#include <openthread/types.h>
+#include <openthread/platform/logging.h>
+
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+#include "api/link_raw.hpp"
+#endif
+#include "common/code_utils.hpp"
+#include "coap/coap.hpp"
+#if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
+#include "crypto/heap.hpp"
+#include "crypto/mbedtls.hpp"
+#endif
+#include "net/ip6.hpp"
+#include "thread/thread_netif.hpp"
+
+
+/**
+ * @addtogroup core-instance
+ *
+ * @brief
+ *   This module includes definitions for OpenThread instance.
+ *
+ * @{
+ *
+ */
+
+/**
+ * This struct represents an opaque (and empty) type corresponding to an OpenThread instance object.
+ *
+ */
+typedef struct otInstance
+{
+} otInstance;
+
+namespace ot {
+
+/**
+ * This class represents an OpenThread instance.
+ *
+ * This class contains all the components used by OpenThread.
+ *
+ */
+class Instance : public otInstance
+{
+public:
+
+#if  OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
+    /**
+      * This static method initializes the OpenThread instance.
+      *
+      * This function must be called before any other calls on OpenThread instance.
+      *
+      * @param[in]    aBuffer      The buffer for OpenThread to use for allocating the Instance.
+      * @param[inout] aBufferSize  On input, the size of `aBuffer`. On output, if not enough space for `Instance`, the
+                                   number of bytes required for `Instance`.
+      *
+      * @returns  A pointer to the new OpenThread instance.
+      *
+      */
+    static Instance *Init(void *aBuffer, size_t *aBufferSize);
+
+#else // OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
+
+    /**
+     * This static method initializes the single OpenThread instance.
+     *
+     * This method initializes OpenThread and prepares it for subsequent OpenThread API calls. This function must be
+     * called before any other calls to OpenThread.
+     *
+     * @returns A reference to the single OpenThread instance.
+     *
+     */
+    static Instance &InitSingle(void);
+
+    /**
+     * This static method returns a reference to the single OpenThread instance.
+     *
+     * @returns A reference to the single OpenThread instance.
+     *
+     */
+    static Instance &Get(void);
+#endif
+
+    /**
+     * This method indicates whether or not the instance is valid/initialized and not yet finalized.
+     *
+     * @returns TRUE if the instance is valid/initialized, FALSE otherwise.
+     *
+     */
+    bool IsInitialized(void) const { return mIsInitialized; }
+
+    /**
+     * This method finalizes the OpenThread instance.
+     *
+     * This method should be called when OpenThread instance is no longer in use.
+     *
+     */
+    void Finalize(void);
+
+    /**
+     * This method registers a callback to indicate when certain configuration or state changes within OpenThread.
+     *
+     * @param[in]  aCallback  A pointer to a function that is called with certain configuration or state changes.
+     * @param[in]  aContext   A pointer to application-specific context.
+     *
+     * @retval OT_ERROR_NONE     Added the callback to the list of callbacks and registered it with OpenThread.
+     * @retval OT_ERROR_NO_BUFS  Could not add the callback due to resource constraints.
+     *
+     */
+    otError RegisterStateChangedCallback(otStateChangedCallback aCallback, void *aContext);
+
+    /**
+     * This method removes/unregisters a previously registered "state changed" callback.
+     *
+     * @param[in]  aCallback         A pointer to the callback function pointer.
+     * @param[in]  aCallbackContext  A pointer to application-specific context.
+     *
+     */
+    void RemoveStateChangedCallback(otStateChangedCallback aCallback, void *aCallbackContext);
+
+    /**
+     * This method triggers a platform reset.
+     *
+     * The reset process ensures that all the OpenThread state/info (stored in volatile memory) is erased. Note that
+     * this method does not erase any persistent state/info saved in non-volatile memory.
+     *
+     */
+    void Reset(void);
+
+    /**
+     * This method deletes all the settings stored in non-volatile memory, and then triggers a platform reset.
+     *
+     */
+    void FactoryReset(void);
+
+    /**
+     * This method erases all the OpenThread persistent info (network settings) stored in non-volatile memory.
+     *
+     * Erase is successful/allowed only if the device is in `disabled` state/role.
+     *
+     * @retval OT_ERROR_NONE           All persistent info/state was erased successfully.
+     * @retval OT_ERROR_INVALID_STATE  Device is not in `disabled` state/role.
+     *
+     */
+    otError ErasePersistentInfo(void);
+
+#if OPENTHREAD_CONFIG_ENABLE_DYNAMIC_LOG_LEVEL
+    /**
+     * This method returns the current dynamic log level.
+     *
+     * @returns the currently set dynamic log level.
+     *
+     */
+    otLogLevel GetDynamicLogLevel(void) const { return mLogLevel; }
+
+    /**
+     * This method sets the dynamic log level.
+     *
+     * @param[in]  aLogLevel The dynamic log level.
+     *
+     */
+    void SetDynamicLogLevel(otLogLevel aLogLevel) { mLogLevel = aLogLevel; }
+#endif
+
+    /**
+     * This method registers the active scan callback.
+     *
+     * Subsequent calls to this method will overwrite the previous callback handler.
+     *
+     * @param[in]  aCallback   A pointer to the callback function pointer.
+     * @param[in]  aContext    A pointer to application-specific context.
+     *
+     */
+    void RegisterActiveScanCallback(otHandleActiveScanResult aCallback, void *aContext);
+
+    /**
+     * This method invokes the previously registered active scan callback with a given scan result.
+     *
+     * @param[in]  aResult     A pointer to active scan result.
+     *
+     */
+    void InvokeActiveScanCallback(otActiveScanResult *aResult) const;
+
+    /**
+     * This method registers the energy scan callback.
+     *
+     * Subsequent calls to this method will overwrite the previous callback handler.
+     *
+     * @param[in]  aCallback   A pointer to the callback function pointer.
+     * @param[in]  aContext    A pointer to application-specific context.
+     *
+     */
+    void RegisterEnergyScanCallback(otHandleEnergyScanResult aCallback, void *aContext);
+
+    /**
+     * This method invokes the previously registered energy scan callback with a given result.
+     *
+     * @param[in]  aResult     A pointer to energy scan result.
+     *
+     */
+    void InvokeEnergyScanCallback(otEnergyScanResult *aResult) const;
+
+    /**
+     * This method returns a reference to the tasklet scheduler object.
+     *
+     * @returns A reference to the tasklet scheduler object.
+     *
+     */
+    TaskletScheduler &GetTaskletScheduler(void) { return mTaskletScheduler; }
+
+    /**
+     * This method returns a reference to the timer milli scheduler object.
+     *
+     * @returns A reference to the timer milli scheduler object.
+     *
+     */
+    TimerMilliScheduler &GetTimerMilliScheduler(void) { return mTimerMilliScheduler; }
+
+#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
+    /**
+     * This method returns a reference to the timer micro scheduler object.
+     *
+     * @returns A reference to the timer micro scheduler object.
+     *
+     */
+    TimerMicroScheduler &GetTimerMicroScheduler(void) { return mTimerMicroScheduler; }
+#endif
+
+#if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
+    /**
+     * This method returns a reference to the MbedTlsHeap object.
+     *
+     * @returns A reference to the MbedTlsHeap object.
+     *
+     */
+    Crypto::Heap &GetMbedTlsHeap(void) { return mMbedTlsHeap; }
+#endif
+
+    /**
+     * This method returns a reference to the Ip6 object.
+     *
+     * @returns A reference to the Ip6 object.
+     *
+     */
+    Ip6::Ip6 &GetIp6(void) { return mIp6; }
+
+    /**
+     * This method returns a reference to the Thread Netif object.
+     *
+     * @returns A reference to the Thread Netif object.
+     *
+     */
+    ThreadNetif &GetThreadNetif(void) { return mThreadNetif; }
+
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+    /**
+     * This method returns a reference to LinkRaw object.
+     *
+     * @returns A reference to the LinkRaw object.
+     *
+     */
+    LinkRaw &GetLinkRaw(void) { return mLinkRaw; }
+#endif
+
+#if OPENTHREAD_ENABLE_APPLICATION_COAP
+    /**
+     * This method returns a reference to application COAP object.
+     *
+     * @returns A reference to the application COAP object.
+     *
+     */
+    Coap::ApplicationCoap &GetApplicationCoap(void) { return mApplicationCoap; }
+#endif
+
+    /**
+     * This method returns a reference to message pool object.
+     *
+     * @returns A reference to the message pool object.
+     *
+     */
+    MessagePool &GetMessagePool(void) { return mMessagePool; }
+
+private:
+    Instance(void);
+    void AfterInit(void);
+
+    enum
+    {
+        kMaxNetifCallbacks = OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS,
+    };
+
+    Ip6::NetifCallback          mNetifCallback[kMaxNetifCallbacks];
+    otHandleActiveScanResult    mActiveScanCallback;
+    void                       *mActiveScanCallbackContext;
+    otHandleEnergyScanResult    mEnergyScanCallback;
+    void                       *mEnergyScanCallbackContext;
+
+    TaskletScheduler            mTaskletScheduler;
+    TimerMilliScheduler         mTimerMilliScheduler;
+
+#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
+    TimerMicroScheduler         mTimerMicroScheduler;
+#endif
+
+#if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
+    Crypto::MbedTls             mMbedTls;
+    Crypto::Heap                mMbedTlsHeap;
+#endif
+
+    Ip6::Ip6                    mIp6;
+    ThreadNetif                 mThreadNetif;
+
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+    LinkRaw                     mLinkRaw;
+#endif
+
+#if OPENTHREAD_ENABLE_APPLICATION_COAP
+    Coap::ApplicationCoap       mApplicationCoap;
+#endif
+
+#if OPENTHREAD_CONFIG_ENABLE_DYNAMIC_LOG_LEVEL
+    otLogLevel                  mLogLevel;
+#endif
+
+    MessagePool                 mMessagePool;
+    bool                        mIsInitialized;
+};
+
+/**
+ * @}
+ *
+ */
+
+}  // namespace ot
+
+#endif  // INSTANCE_HPP_
diff --git a/src/core/common/locator.cpp b/src/core/common/locator.cpp
index 5317cdb..27cb197 100644
--- a/src/core/common/locator.cpp
+++ b/src/core/common/locator.cpp
@@ -35,19 +35,26 @@
 
 #include "locator.hpp"
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 #include "net/ip6.hpp"
 
 namespace ot {
 
+#if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
+Instance &InstanceLocator::GetInstance(void) const
+{
+    return Instance::Get();
+}
+#endif
+
 Ip6::Ip6 &InstanceLocator::GetIp6(void) const
 {
-    return GetInstance().mIp6;
+    return GetInstance().GetIp6();
 }
 
 ThreadNetif &InstanceLocator::GetNetif(void) const
 {
-    return GetInstance().mThreadNetif;
+    return GetInstance().GetThreadNetif();
 }
 
 }  // namespace ot
diff --git a/src/core/common/locator.hpp b/src/core/common/locator.hpp
index 4a27fc8..09cf054 100644
--- a/src/core/common/locator.hpp
+++ b/src/core/common/locator.hpp
@@ -38,13 +38,13 @@
 
 #include <openthread/types.h>
 
-#include "openthread-single-instance.h"
-
 namespace ot {
 
+class Instance;
 class ThreadNetif;
 namespace Ip6 { class Ip6; }
 
+
 /**
  * @addtogroup core-locator
  *
@@ -57,22 +57,29 @@
 
 
 /**
- * This class implements locator for  otInstance object.
+ * This class implements a locator for an OpenThread Instance object.
+ *
+ * The `InstanceLocator` is used as base class of almost all other OpenThread classes. It provides a way for an object
+ * to get to its owning/parent OpenThread `Instance` and other objects within the OpenTread hierarchy (e.g. the
+ * `ThreadNetif` or `Ip6::Ip6` objects).
+ *
+ * If multiple-instance feature is supported, the owning/parent OpenThread `Instance` is tracked as a reference. In the
+ * single-instance case, this class becomes an empty base class.
  *
  */
 class InstanceLocator
 {
 public:
     /**
-     * This method returns a reference to the parent otInstance structure.
+     * This method returns a reference to the parent OpenThread Instance.
      *
-     * @returns A reference to the parent otInstance structure.
+     * @returns A reference to the parent otInstance.
      *
      */
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
-    otInstance &GetInstance(void) const { return mInstance; }
+    Instance &GetInstance(void) const { return mInstance; }
 #else
-    otInstance &GetInstance(void) const { return *otGetInstance(); }
+    Instance &GetInstance(void) const;
 #endif
 
     /**
@@ -98,7 +105,7 @@
      * @param[in]  aInstance  A pointer to the otInstance.
      *
      */
-    InstanceLocator(otInstance &aInstance)
+    InstanceLocator(Instance &aInstance)
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
         : mInstance(aInstance)
 #endif
@@ -108,7 +115,7 @@
 
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
 private:
-    otInstance &mInstance;
+    Instance &mInstance;
 #endif
 };
 
diff --git a/src/core/common/logging.cpp b/src/core/common/logging.cpp
index 59fb0b7..f85c274 100644
--- a/src/core/common/logging.cpp
+++ b/src/core/common/logging.cpp
@@ -37,6 +37,8 @@
 
 #include <openthread/openthread.h>
 
+#include "common/instance.hpp"
+
 /*
  * Verify debug uart dependency.
  *
diff --git a/src/core/common/logging.hpp b/src/core/common/logging.hpp
index 78d86e6..f6b90a1 100644
--- a/src/core/common/logging.hpp
+++ b/src/core/common/logging.hpp
@@ -1517,7 +1517,7 @@
 /**
 * Local/private macro to format the log message
 */
-#define _otLogFormatter(aInstance, aLogLevel, aRegion, aFormat, ...)         \
+#define _otLogFormatter(aInstance, aLogLevel, aRegion, aFormat, ...)        \
     _otDynamicLog(                                                          \
         aInstance,                                                          \
         aLogLevel,                                                          \
diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp
index f753413..ba65201 100644
--- a/src/core/common/message.cpp
+++ b/src/core/common/message.cpp
@@ -35,15 +35,15 @@
 
 #include "message.hpp"
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "net/ip6.hpp"
 
 namespace ot {
 
-MessagePool::MessagePool(otInstance &aInstance) :
+MessagePool::MessagePool(Instance &aInstance) :
     InstanceLocator(aInstance),
     mAllQueue()
 {
@@ -149,7 +149,7 @@
 {
     while (aNumBuffers > GetFreeBufferCount())
     {
-        MeshForwarder &meshForwarder = GetInstance().mThreadNetif.GetMeshForwarder();
+        MeshForwarder &meshForwarder = GetInstance().GetThreadNetif().GetMeshForwarder();
         SuccessOrExit(meshForwarder.EvictIndirectMessage());
     }
 
@@ -168,6 +168,13 @@
     }
 }
 
+#if OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
+uint16_t MessagePool::GetFreeBufferCount(void) const
+{
+    return otPlatMessagePoolNumFreeBuffers(&GetInstance());
+}
+#endif
+
 Message *MessagePool::Iterator::Next(void) const
 {
     Message *next;
diff --git a/src/core/common/message.hpp b/src/core/common/message.hpp
index 772390b..ab20f60 100644
--- a/src/core/common/message.hpp
+++ b/src/core/common/message.hpp
@@ -1140,7 +1140,7 @@
      * This constructor initializes the object.
      *
      */
-    MessagePool(otInstance &aInstance);
+    MessagePool(Instance &aInstance);
 
     /**
      * This method is used to obtain a new message. The default priority `kDefaultMessagePriority`
@@ -1187,7 +1187,7 @@
      *
      */
 #if OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
-    uint16_t GetFreeBufferCount(void) const { return otPlatMessagePoolNumFreeBuffers(&GetInstance()); }
+    uint16_t GetFreeBufferCount(void) const;
 #else
     uint16_t GetFreeBufferCount(void) const { return mNumFreeBuffers; }
 #endif
diff --git a/src/core/common/tasklet.cpp b/src/core/common/tasklet.cpp
index 26c5516..b6b05f0 100644
--- a/src/core/common/tasklet.cpp
+++ b/src/core/common/tasklet.cpp
@@ -35,14 +35,14 @@
 
 #include <openthread/openthread.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "net/ip6.hpp"
 
 namespace ot {
 
-Tasklet::Tasklet(otInstance &aInstance, Handler aHandler, void *aContext):
+Tasklet::Tasklet(Instance &aInstance, Handler aHandler, void *aContext):
     InstanceLocator(aInstance),
     Context(aContext),
     mHandler(aHandler),
@@ -52,7 +52,7 @@
 
 otError Tasklet::Post(void)
 {
-    return GetInstance().mTaskletScheduler.Post(*this);
+    return GetInstance().GetTaskletScheduler().Post(*this);
 }
 
 TaskletScheduler::TaskletScheduler(void):
diff --git a/src/core/common/tasklet.hpp b/src/core/common/tasklet.hpp
index 8d4b1b9..784fc07 100644
--- a/src/core/common/tasklet.hpp
+++ b/src/core/common/tasklet.hpp
@@ -82,7 +82,7 @@
      * @param[in]  aContext    A pointer to arbitrary context information.
      *
      */
-    Tasklet(otInstance &aInstance, Handler aHandler, void *aContext);
+    Tasklet(Instance &aInstance, Handler aHandler, void *aContext);
 
     /**
      * This method puts the tasklet on the run queue.
diff --git a/src/core/common/timer.cpp b/src/core/common/timer.cpp
index 7787bbc..a5c675a 100644
--- a/src/core/common/timer.cpp
+++ b/src/core/common/timer.cpp
@@ -35,9 +35,9 @@
 
 #include "timer.hpp"
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 
 namespace ot {
@@ -87,7 +87,7 @@
 
 TimerMilliScheduler &TimerMilli::GetTimerMilliScheduler(void) const
 {
-    return GetInstance().mTimerMilliScheduler;
+    return GetInstance().GetTimerMilliScheduler();
 }
 
 void TimerScheduler::Add(Timer &aTimer, const AlarmApi &aAlarmApi)
@@ -213,10 +213,12 @@
 
 extern "C" void otPlatAlarmMilliFired(otInstance *aInstance)
 {
+    Instance *instance = static_cast<Instance *>(aInstance);
+
     otLogFuncEntry();
 
     VerifyOrExit(otInstanceIsInitialized(aInstance));
-    aInstance->mTimerMilliScheduler.ProcessTimers();
+    instance->GetTimerMilliScheduler().ProcessTimers();
 
 exit:
     otLogFuncExit();
@@ -244,15 +246,17 @@
 
 TimerMicroScheduler &TimerMicro::GetTimerMicroScheduler(void) const
 {
-    return GetInstance().mTimerMicroScheduler;
+    return GetInstance().GetTimerMicroScheduler();
 }
 
 extern "C" void otPlatAlarmMicroFired(otInstance *aInstance)
 {
+    Instance *instance = static_cast<Instance *>(aInstance);
+
     otLogFuncEntry();
 
     VerifyOrExit(otInstanceIsInitialized(aInstance));
-    aInstance->mTimerMicroScheduler.ProcessTimers();
+    instance->GetTimerMicroScheduler().ProcessTimers();
 
 exit:
     otLogFuncExit();
diff --git a/src/core/common/timer.hpp b/src/core/common/timer.hpp
index 013365a..de7f424 100644
--- a/src/core/common/timer.hpp
+++ b/src/core/common/timer.hpp
@@ -93,7 +93,7 @@
      * @param[in]  aContext    A pointer to arbitrary context information.
      *
      */
-    Timer(otInstance &aInstance, Handler aHandler, void *aContext):
+    Timer(Instance &aInstance, Handler aHandler, void *aContext):
         InstanceLocator(aInstance),
         Context(aContext),
         mHandler(aHandler),
@@ -153,7 +153,7 @@
      * @param[in]  aContext    A pointer to arbitrary context information.
      *
      */
-    TimerMilli(otInstance &aInstance, Handler aHandler, void *aContext):
+    TimerMilli(Instance &aInstance, Handler aHandler, void *aContext):
         Timer(aInstance, aHandler, aContext) {
     }
 
@@ -243,7 +243,7 @@
      * @param[in]  aInstance  A reference to the instance object.
      *
      */
-    TimerScheduler(otInstance &aInstance):
+    TimerScheduler(Instance &aInstance):
         InstanceLocator(aInstance),
         mHead(NULL) {
     }
@@ -313,7 +313,7 @@
      * @param[in]  aInstance  A reference to the instance object.
      *
      */
-    TimerMilliScheduler(otInstance &aInstance):
+    TimerMilliScheduler(Instance &aInstance):
         TimerScheduler(aInstance) {
     }
 
@@ -361,7 +361,7 @@
      * @param[in]  aContext    A pointer to arbitrary context information.
      *
      */
-    TimerMicro(otInstance &aInstance, Handler aHandler, void *aContext):
+    TimerMicro(Instance &aInstance, Handler aHandler, void *aContext):
         Timer(aInstance, aHandler, aContext) {
     }
 
@@ -421,7 +421,7 @@
      * @param[in]  aInstance  A reference to the instance object.
      *
      */
-    TimerMicroScheduler(otInstance &aInstance):
+    TimerMicroScheduler(Instance &aInstance):
         TimerScheduler(aInstance) {
     }
 
diff --git a/src/core/common/trickle_timer.cpp b/src/core/common/trickle_timer.cpp
index 38f2ad9..30b70dc 100644
--- a/src/core/common/trickle_timer.cpp
+++ b/src/core/common/trickle_timer.cpp
@@ -41,7 +41,7 @@
 namespace ot {
 
 TrickleTimer::TrickleTimer(
-    otInstance &aInstance,
+    Instance &aInstance,
 #ifdef ENABLE_TRICKLE_TIMER_SUPPRESSION_SUPPORT
     uint32_t aRedundancyConstant,
 #endif
diff --git a/src/core/common/trickle_timer.hpp b/src/core/common/trickle_timer.hpp
index 6437cc5..e3dc2dc 100644
--- a/src/core/common/trickle_timer.hpp
+++ b/src/core/common/trickle_timer.hpp
@@ -89,7 +89,7 @@
      * @param[in]  aContext                 A pointer to arbitrary context information.
      *
      */
-    TrickleTimer(otInstance &aInstance,
+    TrickleTimer(Instance &aInstance,
 #ifdef ENABLE_TRICKLE_TIMER_SUPPRESSION_SUPPORT
                  uint32_t aRedundancyConstant,
 #endif
diff --git a/src/core/crypto/mbedtls.cpp b/src/core/crypto/mbedtls.cpp
index 934ed6e..21f40be 100644
--- a/src/core/crypto/mbedtls.cpp
+++ b/src/core/crypto/mbedtls.cpp
@@ -36,8 +36,7 @@
 #include <mbedtls/platform.h>
 
 #include "heap.hpp"
-#include "openthread-instance.h"
-#include "openthread-single-instance.h"
+#include "common/instance.hpp"
 
 #if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
 
@@ -46,12 +45,12 @@
 
 static void *CAlloc(size_t aCount, size_t aSize)
 {
-    return otGetInstance()->mMbedTlsHeap.CAlloc(aCount, aSize);
+    return Instance::Get().GetMbedTlsHeap().CAlloc(aCount, aSize);
 }
 
 static void Free(void *aPointer)
 {
-    otGetInstance()->mMbedTlsHeap.Free(aPointer);
+    Instance::Get().GetMbedTlsHeap().Free(aPointer);
 }
 
 MbedTls::MbedTls(void)
diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp
index 7c53612..72748c8 100644
--- a/src/core/mac/mac.cpp
+++ b/src/core/mac/mac.cpp
@@ -39,10 +39,10 @@
 
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "crypto/aes_ccm.hpp"
 #include "crypto/sha256.hpp"
@@ -136,7 +136,7 @@
     }
 }
 
-Mac::Mac(otInstance &aInstance):
+Mac::Mac(Instance &aInstance):
     InstanceLocator(aInstance),
     mOperation(kOperationIdle),
     mPendingActiveScan(false),
@@ -335,18 +335,20 @@
 
 extern "C" void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi)
 {
-    VerifyOrExit(otInstanceIsInitialized(aInstance));
+    Instance *instance = static_cast<Instance *>(aInstance);
+
+    VerifyOrExit(instance->IsInitialized());
 
 #if OPENTHREAD_ENABLE_RAW_LINK_API
 
-    if (aInstance->mLinkRaw.IsEnabled())
+    if (instance->GetLinkRaw().IsEnabled())
     {
-        aInstance->mLinkRaw.InvokeEnergyScanDone(aEnergyScanMaxRssi);
+        instance->GetLinkRaw().InvokeEnergyScanDone(aEnergyScanMaxRssi);
     }
     else
 #endif // OPENTHREAD_ENABLE_RAW_LINK_API
     {
-        aInstance->mThreadNetif.GetMac().EnergyScanDone(aEnergyScanMaxRssi);
+        instance->GetThreadNetif().GetMac().EnergyScanDone(aEnergyScanMaxRssi);
     }
 
 exit:
@@ -935,9 +937,11 @@
 
 extern "C" void otPlatRadioTxStarted(otInstance *aInstance, otRadioFrame *aFrame)
 {
+    Instance *instance = static_cast<Instance *>(aInstance);
+
     otLogFuncEntry();
-    VerifyOrExit(otInstanceIsInitialized(aInstance));
-    aInstance->mThreadNetif.GetMac().TransmitStartedTask(aFrame);
+    VerifyOrExit(instance->IsInitialized());
+    instance->GetThreadNetif().GetMac().TransmitStartedTask(aFrame);
 exit:
     otLogFuncExit();
 }
@@ -956,19 +960,21 @@
 extern "C" void otPlatRadioTxDone(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame,
                                   otError aError)
 {
+    Instance *instance = static_cast<Instance *>(aInstance);
+
     otLogFuncEntryMsg("%!otError!", aError);
-    VerifyOrExit(otInstanceIsInitialized(aInstance));
+    VerifyOrExit(instance->IsInitialized());
 
 #if OPENTHREAD_ENABLE_RAW_LINK_API
 
-    if (aInstance->mLinkRaw.IsEnabled())
+    if (instance->GetLinkRaw().IsEnabled())
     {
-        aInstance->mLinkRaw.InvokeTransmitDone(aFrame, aAckFrame, aError);
+        instance->GetLinkRaw().InvokeTransmitDone(aFrame, aAckFrame, aError);
     }
     else
 #endif // OPENTHREAD_ENABLE_RAW_LINK_API
     {
-        aInstance->mThreadNetif.GetMac().TransmitDoneTask(aFrame, aAckFrame, aError);
+        instance->GetThreadNetif().GetMac().TransmitDoneTask(aFrame, aAckFrame, aError);
     }
 
 exit:
@@ -1040,9 +1046,9 @@
 
     default:
 #if OPENTHREAD_ENABLE_RAW_LINK_API
-        if (GetInstance().mLinkRaw.IsEnabled())
+        if (GetInstance().GetLinkRaw().IsEnabled())
         {
-            GetInstance().mLinkRaw.InvokeTransmitDone(mTxFrame, NULL, OT_ERROR_NO_ACK);
+            GetInstance().GetLinkRaw().InvokeTransmitDone(mTxFrame, NULL, OT_ERROR_NO_ACK);
         }
         else
 #endif
@@ -1501,19 +1507,21 @@
 
 extern "C" void otPlatRadioReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
 {
+    Instance *instance = static_cast<Instance *>(aInstance);
+
     otLogFuncEntryMsg("%!otError!", aError);
-    VerifyOrExit(otInstanceIsInitialized(aInstance));
+    VerifyOrExit(instance->IsInitialized());
 
 #if OPENTHREAD_ENABLE_RAW_LINK_API
 
-    if (aInstance->mLinkRaw.IsEnabled())
+    if (instance->GetLinkRaw().IsEnabled())
     {
-        aInstance->mLinkRaw.InvokeReceiveDone(aFrame, aError);
+        instance->GetLinkRaw().InvokeReceiveDone(aFrame, aError);
     }
     else
 #endif // OPENTHREAD_ENABLE_RAW_LINK_API
     {
-        aInstance->mThreadNetif.GetMac().ReceiveDoneTask(static_cast<Frame *>(aFrame), aError);
+        instance->GetThreadNetif().GetMac().ReceiveDoneTask(static_cast<Frame *>(aFrame), aError);
     }
 
 exit:
@@ -1896,6 +1904,11 @@
     memset(&mCounters, 0, sizeof(mCounters));
 }
 
+int8_t Mac::GetNoiseFloor(void)
+{
+    return otPlatRadioGetReceiveSensitivity(&GetInstance());
+}
+
 #if OPENTHREAD_CONFIG_ENABLE_BEACON_RSP_WHEN_JOINABLE
 bool Mac::IsBeaconJoinable(void)
 {
@@ -1922,7 +1935,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     Mac &mac = *static_cast<Mac *>(aContext.GetContext());
 #else
-    Mac &mac = otGetInstance()->mThreadNetif.GetMac();
+    Mac &mac = Instance::Get().GetThreadNetif().GetMac();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return mac;
diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp
index 506b26a..3ddd8dd 100644
--- a/src/core/mac/mac.hpp
+++ b/src/core/mac/mac.hpp
@@ -220,7 +220,7 @@
      * @param[in]  aInstance  A reference to the OpenThread instance.
      *
      */
-    explicit Mac(otInstance &aInstance);
+    explicit Mac(Instance &aInstance);
 
     /**
      * This function pointer is called on receiving an IEEE 802.15.4 Beacon during an Active Scan.
@@ -602,7 +602,7 @@
      * @returns The noise floor value in dBm.
      *
      */
-    int8_t GetNoiseFloor(void) { return otPlatRadioGetReceiveSensitivity(&GetInstance()); }
+    int8_t GetNoiseFloor(void);
 
     /**
      * This method indicates whether or not CSMA backoff is supported by the radio layer.
diff --git a/src/core/mac/mac_filter.cpp b/src/core/mac/mac_filter.cpp
index d5c8a47..17ccc59 100644
--- a/src/core/mac/mac_filter.cpp
+++ b/src/core/mac/mac_filter.cpp
@@ -33,7 +33,7 @@
 
 #include "mac_filter.hpp"
 
-#include "openthread/types.h"
+#include <openthread/types.h>
 #include "utils/wrap_string.h"
 
 #include "common/code_utils.hpp"
diff --git a/src/core/mac/mac_frame.cpp b/src/core/mac/mac_frame.cpp
index 6557bf6..ac79044 100644
--- a/src/core/mac/mac_frame.cpp
+++ b/src/core/mac/mac_frame.cpp
@@ -38,6 +38,7 @@
 
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 
 namespace ot {
 namespace Mac {
diff --git a/src/core/meshcop/announce_begin_client.cpp b/src/core/meshcop/announce_begin_client.cpp
index 2075965..eb5d6ac 100644
--- a/src/core/meshcop/announce_begin_client.cpp
+++ b/src/core/meshcop/announce_begin_client.cpp
@@ -37,10 +37,10 @@
 
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "coap/coap_header.hpp"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "meshcop/meshcop.hpp"
 #include "meshcop/meshcop_tlvs.hpp"
@@ -51,7 +51,7 @@
 
 namespace ot {
 
-AnnounceBeginClient::AnnounceBeginClient(otInstance &aInstance):
+AnnounceBeginClient::AnnounceBeginClient(Instance &aInstance):
     InstanceLocator(aInstance)
 {
 }
diff --git a/src/core/meshcop/announce_begin_client.hpp b/src/core/meshcop/announce_begin_client.hpp
index 99526ea..1fd0f18 100644
--- a/src/core/meshcop/announce_begin_client.hpp
+++ b/src/core/meshcop/announce_begin_client.hpp
@@ -54,7 +54,7 @@
      * This constructor initializes the object.
      *
      */
-    AnnounceBeginClient(otInstance &aInstance);
+    AnnounceBeginClient(Instance &aInstance);
 
     /**
      * This method sends a Announce Begin message.
diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp
index 20751e4..9491c95 100644
--- a/src/core/meshcop/commissioner.cpp
+++ b/src/core/meshcop/commissioner.cpp
@@ -41,9 +41,9 @@
 #include <openthread/types.h>
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "coap/coap_header.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "crypto/pbkdf2_cmac.h"
 #include "meshcop/joiner_router.hpp"
@@ -60,7 +60,7 @@
 namespace ot {
 namespace MeshCoP {
 
-Commissioner::Commissioner(otInstance &aInstance):
+Commissioner::Commissioner(Instance &aInstance):
     InstanceLocator(aInstance),
     mState(OT_COMMISSIONER_STATE_DISABLED),
     mJoinerPort(0),
@@ -1088,7 +1088,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     Commissioner &commissioner = *static_cast<Commissioner *>(aContext.GetContext());
 #else
-    Commissioner &commissioner = otGetThreadNetif().GetCommissioner();
+    Commissioner &commissioner = Instance::Get().GetThreadNetif().GetCommissioner();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return commissioner;
diff --git a/src/core/meshcop/commissioner.hpp b/src/core/meshcop/commissioner.hpp
index ae5a7fa..d97295b 100644
--- a/src/core/meshcop/commissioner.hpp
+++ b/src/core/meshcop/commissioner.hpp
@@ -65,7 +65,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    Commissioner(otInstance &aInstance);
+    Commissioner(Instance &aInstance);
 
     /**
      * This method starts the Commissioner service.
diff --git a/src/core/meshcop/dataset.cpp b/src/core/meshcop/dataset.cpp
index fe93bfb..e0d2415 100644
--- a/src/core/meshcop/dataset.cpp
+++ b/src/core/meshcop/dataset.cpp
@@ -36,8 +36,8 @@
 
 #include <stdio.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "common/settings.hpp"
 #include "meshcop/meshcop_tlvs.hpp"
 #include "thread/mle_tlvs.hpp"
diff --git a/src/core/meshcop/dataset_local.cpp b/src/core/meshcop/dataset_local.cpp
index cf56b6a..aa13ebe 100644
--- a/src/core/meshcop/dataset_local.cpp
+++ b/src/core/meshcop/dataset_local.cpp
@@ -42,6 +42,7 @@
 
 #include "common/code_utils.hpp"
 #include "common/logging.hpp"
+#include "common/instance.hpp"
 #include "common/settings.hpp"
 #include "meshcop/dataset.hpp"
 #include "meshcop/meshcop_tlvs.hpp"
@@ -50,7 +51,7 @@
 namespace ot {
 namespace MeshCoP {
 
-DatasetLocal::DatasetLocal(otInstance &aInstance, const Tlv::Type aType) :
+DatasetLocal::DatasetLocal(Instance &aInstance, const Tlv::Type aType) :
     InstanceLocator(aInstance),
     mUpdateTime(0),
     mType(aType)
diff --git a/src/core/meshcop/dataset_local.hpp b/src/core/meshcop/dataset_local.hpp
index 092daf9..44367bf 100644
--- a/src/core/meshcop/dataset_local.hpp
+++ b/src/core/meshcop/dataset_local.hpp
@@ -54,7 +54,7 @@
      * @param[in]  aType      The type of the dataset, active or pending.
      *
      */
-    DatasetLocal(otInstance &aInstance, const Tlv::Type aType);
+    DatasetLocal(Instance &aInstance, const Tlv::Type aType);
 
     /**
      * This method indicates whether this is an Active or Pending Dataset.
diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp
index fb62a3e..54bd0c1 100644
--- a/src/core/meshcop/dataset_manager.cpp
+++ b/src/core/meshcop/dataset_manager.cpp
@@ -46,6 +46,7 @@
 #include "common/code_utils.hpp"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/timer.hpp"
 #include "meshcop/dataset.hpp"
@@ -59,7 +60,7 @@
 namespace ot {
 namespace MeshCoP {
 
-DatasetManager::DatasetManager(otInstance &aInstance, const Tlv::Type aType, const char *aUriSet,
+DatasetManager::DatasetManager(Instance &aInstance, const Tlv::Type aType, const char *aUriSet,
                                const char *aUriGet, Timer::Handler aTimerHandler):
     InstanceLocator(aInstance),
     mNetwork(aType),
@@ -953,13 +954,13 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     ActiveDatasetBase &activeDataset = *static_cast<ActiveDatasetBase *>(aContext.GetContext());
 #else
-    ActiveDatasetBase &activeDataset = otGetThreadNetif().GetActiveDataset();
+    ActiveDatasetBase &activeDataset = Instance::Get().GetThreadNetif().GetActiveDataset();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return activeDataset;
 }
 
-ActiveDatasetBase::ActiveDatasetBase(otInstance &aInstance):
+ActiveDatasetBase::ActiveDatasetBase(Instance &aInstance):
     DatasetManager(aInstance, Tlv::kActiveTimestamp, OT_URI_PATH_ACTIVE_SET, OT_URI_PATH_ACTIVE_GET,
                    &ActiveDatasetBase::HandleTimer),
     mResourceGet(OT_URI_PATH_ACTIVE_GET, &ActiveDatasetBase::HandleGet, this)
@@ -1051,13 +1052,13 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     PendingDatasetBase &pendingDataset = *static_cast<PendingDatasetBase *>(aContext.GetContext());
 #else
-    PendingDatasetBase &pendingDataset = otGetThreadNetif().GetPendingDataset();
+    PendingDatasetBase &pendingDataset = Instance::Get().GetThreadNetif().GetPendingDataset();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return pendingDataset;
 }
 
-PendingDatasetBase::PendingDatasetBase(otInstance &aInstance):
+PendingDatasetBase::PendingDatasetBase(Instance &aInstance):
     DatasetManager(aInstance, Tlv::kPendingTimestamp, OT_URI_PATH_PENDING_SET, OT_URI_PATH_PENDING_GET,
                    &PendingDatasetBase::HandleTimer),
     mDelayTimer(aInstance, &PendingDatasetBase::HandleDelayTimer, this),
diff --git a/src/core/meshcop/dataset_manager.hpp b/src/core/meshcop/dataset_manager.hpp
index 1ae609b..b452f68 100644
--- a/src/core/meshcop/dataset_manager.hpp
+++ b/src/core/meshcop/dataset_manager.hpp
@@ -132,7 +132,7 @@
      * @param[in]  aTimerHandler  The registration timer handler.
      *
      */
-    DatasetManager(otInstance &aInstance, const Tlv::Type aType, const char *aUriSet, const char *aUriGet,
+    DatasetManager(Instance &aInstance, const Tlv::Type aType, const char *aUriSet, const char *aUriGet,
                    TimerMilli::Handler aTimerHandler);
 
     /**
@@ -282,7 +282,7 @@
      * @param[in]  aInstance      A reference to the OpenThread instance.
      *
      */
-    ActiveDatasetBase(otInstance &aInstance);
+    ActiveDatasetBase(Instance &aInstance);
 
     /**
      * This method restores the Active Operational Dataset from non-volatile memory.
@@ -364,7 +364,7 @@
      * @param[in]  The Thread network interface.
      *
      */
-    PendingDatasetBase(otInstance &aInstance);
+    PendingDatasetBase(Instance &aInstance);
 
     /**
      * This method restores the Operational Dataset from non-volatile memory.
diff --git a/src/core/meshcop/dataset_manager_ftd.cpp b/src/core/meshcop/dataset_manager_ftd.cpp
index a6f4a32..50b6a03 100644
--- a/src/core/meshcop/dataset_manager_ftd.cpp
+++ b/src/core/meshcop/dataset_manager_ftd.cpp
@@ -42,11 +42,10 @@
 #include <openthread/platform/random.h>
 #include <openthread/platform/radio.h>
 
-#include "common/code_utils.hpp"
-#include "common/debug.hpp"
 #include "coap/coap_header.hpp"
-#include "common/debug.hpp"
 #include "common/code_utils.hpp"
+#include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/timer.hpp"
 #include "meshcop/dataset.hpp"
@@ -60,7 +59,7 @@
 namespace ot {
 namespace MeshCoP {
 
-ActiveDataset::ActiveDataset(otInstance &aInstance):
+ActiveDataset::ActiveDataset(Instance &aInstance):
     ActiveDatasetBase(aInstance),
     mResourceSet(OT_URI_PATH_ACTIVE_SET, &ActiveDataset::HandleSet, this)
 {
@@ -207,7 +206,7 @@
     return;
 }
 
-PendingDataset::PendingDataset(otInstance &aInstance):
+PendingDataset::PendingDataset(Instance &aInstance):
     PendingDatasetBase(aInstance),
     mResourceSet(OT_URI_PATH_PENDING_SET, &PendingDataset::HandleSet, this)
 {
diff --git a/src/core/meshcop/dataset_manager_ftd.hpp b/src/core/meshcop/dataset_manager_ftd.hpp
index d9b0ac5..c23102a 100644
--- a/src/core/meshcop/dataset_manager_ftd.hpp
+++ b/src/core/meshcop/dataset_manager_ftd.hpp
@@ -53,7 +53,7 @@
 class ActiveDataset: public ActiveDatasetBase
 {
 public:
-    ActiveDataset(otInstance &aInstance);
+    ActiveDataset(Instance &aInstance);
 
     otError GenerateLocal(void);
 
@@ -74,7 +74,7 @@
 class PendingDataset: public PendingDatasetBase
 {
 public:
-    PendingDataset(otInstance &aInstance);
+    PendingDataset(Instance &aInstance);
 
     void StartLeader(void);
 
diff --git a/src/core/meshcop/dataset_manager_mtd.hpp b/src/core/meshcop/dataset_manager_mtd.hpp
index 23e7f08..57104f5 100644
--- a/src/core/meshcop/dataset_manager_mtd.hpp
+++ b/src/core/meshcop/dataset_manager_mtd.hpp
@@ -48,7 +48,7 @@
 class ActiveDataset: public ActiveDatasetBase
 {
 public:
-    ActiveDataset(otInstance &aInstance) : ActiveDatasetBase(aInstance) { }
+    ActiveDataset(Instance &aInstance) : ActiveDatasetBase(aInstance) { }
 
     otError GenerateLocal(void) { return OT_ERROR_NOT_IMPLEMENTED; }
 };
@@ -56,7 +56,7 @@
 class PendingDataset: public PendingDatasetBase
 {
 public:
-    PendingDataset(otInstance &aInstance) : PendingDatasetBase(aInstance) { }
+    PendingDataset(Instance &aInstance) : PendingDatasetBase(aInstance) { }
 };
 
 }  // namespace MeshCoP
diff --git a/src/core/meshcop/dtls.cpp b/src/core/meshcop/dtls.cpp
index bee8596..f9ce46f 100644
--- a/src/core/meshcop/dtls.cpp
+++ b/src/core/meshcop/dtls.cpp
@@ -38,10 +38,10 @@
 #include <mbedtls/debug.h>
 #include <openthread/platform/radio.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/timer.hpp"
 #include "crypto/sha256.hpp"
@@ -52,7 +52,7 @@
 namespace ot {
 namespace MeshCoP {
 
-Dtls::Dtls(otInstance &aInstance):
+Dtls::Dtls(Instance &aInstance):
     InstanceLocator(aInstance),
     mPskLength(0),
     mStarted(false),
@@ -520,7 +520,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     Dtls &dtls = *static_cast<Dtls *>(aContext.GetContext());
 #else
-    Dtls &dtls = otGetThreadNetif().GetDtls();
+    Dtls &dtls = Instance::Get().GetThreadNetif().GetDtls();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return dtls;
diff --git a/src/core/meshcop/dtls.hpp b/src/core/meshcop/dtls.hpp
index c107b04..49f19e4 100644
--- a/src/core/meshcop/dtls.hpp
+++ b/src/core/meshcop/dtls.hpp
@@ -72,7 +72,7 @@
      * @param[in]  aNetif  A reference to the Thread network interface.
      *
      */
-    Dtls(otInstance &aInstance);
+    Dtls(Instance &aInstance);
 
     /**
      * This function pointer is called when a connection is established or torn down.
diff --git a/src/core/meshcop/energy_scan_client.cpp b/src/core/meshcop/energy_scan_client.cpp
index 124a072..48bd142 100644
--- a/src/core/meshcop/energy_scan_client.cpp
+++ b/src/core/meshcop/energy_scan_client.cpp
@@ -41,6 +41,7 @@
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
 #include "common/encoding.hpp"
+#include "coap/coap_header.hpp"
 #include "common/logging.hpp"
 #include "meshcop/meshcop.hpp"
 #include "meshcop/meshcop_tlvs.hpp"
@@ -54,7 +55,7 @@
 
 namespace ot {
 
-EnergyScanClient::EnergyScanClient(otInstance &aInstance) :
+EnergyScanClient::EnergyScanClient(Instance &aInstance) :
     InstanceLocator(aInstance),
     mEnergyScan(OT_URI_PATH_ENERGY_REPORT, &EnergyScanClient::HandleReport, this)
 {
diff --git a/src/core/meshcop/energy_scan_client.hpp b/src/core/meshcop/energy_scan_client.hpp
index 5f272bf..10563de 100644
--- a/src/core/meshcop/energy_scan_client.hpp
+++ b/src/core/meshcop/energy_scan_client.hpp
@@ -58,7 +58,7 @@
      * This constructor initializes the object.
      *
      */
-    EnergyScanClient(otInstance &aInstance);
+    EnergyScanClient(Instance &aInstance);
 
     /**
      * This method sends an Energy Scan Query message.
diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp
index ff9ea4a..5feccf6 100644
--- a/src/core/meshcop/joiner.cpp
+++ b/src/core/meshcop/joiner.cpp
@@ -44,6 +44,7 @@
 #include "common/crc16.hpp"
 #include "common/debug.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "mac/mac_frame.hpp"
 #include "meshcop/meshcop.hpp"
@@ -58,7 +59,7 @@
 namespace ot {
 namespace MeshCoP {
 
-Joiner::Joiner(otInstance &aInstance):
+Joiner::Joiner(Instance &aInstance):
     InstanceLocator(aInstance),
     mState(OT_JOINER_STATE_IDLE),
     mCallback(NULL),
@@ -618,7 +619,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     Joiner &joiner = *static_cast<Joiner *>(aContext.GetContext());
 #else
-    Joiner &joiner = otGetThreadNetif().GetJoiner();
+    Joiner &joiner = Instance::Get().GetThreadNetif().GetJoiner();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return joiner;
diff --git a/src/core/meshcop/joiner.hpp b/src/core/meshcop/joiner.hpp
index 35aa534..6d6bcb7 100644
--- a/src/core/meshcop/joiner.hpp
+++ b/src/core/meshcop/joiner.hpp
@@ -63,7 +63,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    Joiner(otInstance &aInstance);
+    Joiner(Instance &aInstance);
 
     /**
      * This method starts the Joiner service.
diff --git a/src/core/meshcop/joiner_router.cpp b/src/core/meshcop/joiner_router.cpp
index 3e7c38a..e873e91 100644
--- a/src/core/meshcop/joiner_router.cpp
+++ b/src/core/meshcop/joiner_router.cpp
@@ -39,9 +39,9 @@
 
 #include <stdio.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "meshcop/meshcop.hpp"
 #include "meshcop/meshcop_tlvs.hpp"
@@ -55,9 +55,9 @@
 namespace ot {
 namespace MeshCoP {
 
-JoinerRouter::JoinerRouter(otInstance &aInstance):
+JoinerRouter::JoinerRouter(Instance &aInstance):
     InstanceLocator(aInstance),
-    mSocket(aInstance.mThreadNetif.GetIp6().GetUdp()),
+    mSocket(aInstance.GetThreadNetif().GetIp6().GetUdp()),
     mRelayTransmit(OT_URI_PATH_RELAY_TX, &JoinerRouter::HandleRelayTransmit, this),
     mTimer(aInstance, &JoinerRouter::HandleTimer, this),
     mJoinerUdpPort(0),
@@ -534,7 +534,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     JoinerRouter &joiner = *static_cast<JoinerRouter *>(aContext.GetContext());
 #else
-    JoinerRouter &joiner = otGetThreadNetif().GetJoinerRouter();
+    JoinerRouter &joiner = Instance::Get().GetThreadNetif().GetJoinerRouter();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return joiner;
diff --git a/src/core/meshcop/joiner_router.hpp b/src/core/meshcop/joiner_router.hpp
index dde52d7..3ac2371 100644
--- a/src/core/meshcop/joiner_router.hpp
+++ b/src/core/meshcop/joiner_router.hpp
@@ -63,7 +63,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    JoinerRouter(otInstance &aInstance);
+    JoinerRouter(Instance &aInstance);
 
     /**
      * This method returns the Joiner UDP Port.
diff --git a/src/core/meshcop/leader.cpp b/src/core/meshcop/leader.cpp
index 6c41048..af48949 100644
--- a/src/core/meshcop/leader.cpp
+++ b/src/core/meshcop/leader.cpp
@@ -41,9 +41,9 @@
 
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "coap/coap_header.hpp"
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "meshcop/meshcop.hpp"
 #include "meshcop/meshcop_tlvs.hpp"
@@ -54,7 +54,7 @@
 namespace ot {
 namespace MeshCoP {
 
-Leader::Leader(otInstance &aInstance):
+Leader::Leader(Instance &aInstance):
     InstanceLocator(aInstance),
     mPetition(OT_URI_PATH_LEADER_PETITION, Leader::HandlePetition, this),
     mKeepAlive(OT_URI_PATH_LEADER_KEEP_ALIVE, Leader::HandleKeepAlive, this),
@@ -323,7 +323,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     Leader &leader = *static_cast<Leader *>(aContext.GetContext());
 #else
-    Leader &leader = otGetThreadNetif().GetLeader();
+    Leader &leader = Instance::Get().GetThreadNetif().GetLeader();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return leader;
diff --git a/src/core/meshcop/leader.hpp b/src/core/meshcop/leader.hpp
index 78ec3b1..ea4adca 100644
--- a/src/core/meshcop/leader.hpp
+++ b/src/core/meshcop/leader.hpp
@@ -70,7 +70,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    Leader(otInstance &aInstance);
+    Leader(Instance &aInstance);
 
     /**
      * This method sends a MGMT_DATASET_CHANGED message to commissioner.
diff --git a/src/core/meshcop/panid_query_client.cpp b/src/core/meshcop/panid_query_client.cpp
index b629b46..7e6678a 100644
--- a/src/core/meshcop/panid_query_client.cpp
+++ b/src/core/meshcop/panid_query_client.cpp
@@ -40,6 +40,7 @@
 #include "coap/coap_header.hpp"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "meshcop/meshcop.hpp"
 #include "meshcop/meshcop_tlvs.hpp"
@@ -50,7 +51,7 @@
 
 namespace ot {
 
-PanIdQueryClient::PanIdQueryClient(otInstance &aInstance) :
+PanIdQueryClient::PanIdQueryClient(Instance &aInstance) :
     InstanceLocator(aInstance),
     mCallback(NULL),
     mContext(NULL),
diff --git a/src/core/meshcop/panid_query_client.hpp b/src/core/meshcop/panid_query_client.hpp
index 8dffbc5..84c0e14 100644
--- a/src/core/meshcop/panid_query_client.hpp
+++ b/src/core/meshcop/panid_query_client.hpp
@@ -58,7 +58,7 @@
      * This constructor initializes the object.
      *
      */
-    PanIdQueryClient(otInstance &aInstance);
+    PanIdQueryClient(Instance &aInstance);
 
     /**
      * This method sends a PAN ID Query message.
diff --git a/src/core/net/dhcp6_client.cpp b/src/core/net/dhcp6_client.cpp
index 62303db..15ccb9b 100644
--- a/src/core/net/dhcp6_client.cpp
+++ b/src/core/net/dhcp6_client.cpp
@@ -38,9 +38,9 @@
 #include <openthread/types.h>
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "mac/mac.hpp"
 #include "net/dhcp6.hpp"
@@ -56,9 +56,9 @@
 
 namespace Dhcp6 {
 
-Dhcp6Client::Dhcp6Client(otInstance &aInstance) :
+Dhcp6Client::Dhcp6Client(Instance &aInstance) :
     InstanceLocator(aInstance),
-    mSocket(aInstance.mThreadNetif.GetIp6().GetUdp()),
+    mSocket(aInstance.GetThreadNetif().GetIp6().GetUdp()),
     mTrickleTimer(aInstance, &Dhcp6Client::HandleTrickleTimer, NULL, this),
     mStartTime(0),
     mAddresses(NULL),
@@ -721,7 +721,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     Dhcp6Client &client = *static_cast<Dhcp6Client *>(aContext.GetContext());
 #else
-    Dhcp6Client &client = otGetThreadNetif().GetDhcp6Client();
+    Dhcp6Client &client = Instance::Get().GetThreadNetif().GetDhcp6Client();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return client;
diff --git a/src/core/net/dhcp6_client.hpp b/src/core/net/dhcp6_client.hpp
index 257d4a0..3a3755a 100644
--- a/src/core/net/dhcp6_client.hpp
+++ b/src/core/net/dhcp6_client.hpp
@@ -179,7 +179,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    explicit Dhcp6Client(otInstance &aInstance);
+    explicit Dhcp6Client(Instance &aInstance);
 
     /**
      * This method update addresses that shall be automatically created using DHCP.
diff --git a/src/core/net/dhcp6_server.cpp b/src/core/net/dhcp6_server.cpp
index 6e85b1c..b3c3135 100644
--- a/src/core/net/dhcp6_server.cpp
+++ b/src/core/net/dhcp6_server.cpp
@@ -39,6 +39,7 @@
 
 #include "common/code_utils.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "thread/mle.hpp"
 #include "thread/thread_netif.hpp"
@@ -51,7 +52,7 @@
 namespace ot {
 namespace Dhcp6 {
 
-Dhcp6Server::Dhcp6Server(otInstance &aInstance):
+Dhcp6Server::Dhcp6Server(Instance &aInstance):
     InstanceLocator(aInstance),
     mSocket(GetNetif().GetIp6().GetUdp())
 {
diff --git a/src/core/net/dhcp6_server.hpp b/src/core/net/dhcp6_server.hpp
index 1990c27..ce8c46c 100644
--- a/src/core/net/dhcp6_server.hpp
+++ b/src/core/net/dhcp6_server.hpp
@@ -111,7 +111,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    explicit Dhcp6Server(otInstance &aInstance);
+    explicit Dhcp6Server(Instance &aInstance);
 
     /**
      * This method updates DHCP Agents and DHCP Alocs.
diff --git a/src/core/net/dns_client.cpp b/src/core/net/dns_client.cpp
index 52da324..d5e2e3b 100644
--- a/src/core/net/dns_client.cpp
+++ b/src/core/net/dns_client.cpp
@@ -32,6 +32,7 @@
 
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "net/udp6.hpp"
 #include "thread/thread_netif.hpp"
 
@@ -523,7 +524,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     Client &client = *static_cast<Client *>(aContext.GetContext());
 #else
-    Client &client = otGetThreadNetif().GetDnsClient();
+    Client &client = Instance::Get().GetThreadNetif().GetDnsClient();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return client;
diff --git a/src/core/net/icmp6.cpp b/src/core/net/icmp6.cpp
index 98909d1..3761647 100644
--- a/src/core/net/icmp6.cpp
+++ b/src/core/net/icmp6.cpp
@@ -39,6 +39,7 @@
 
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/message.hpp"
 #include "net/ip6.hpp"
@@ -48,7 +49,7 @@
 namespace ot {
 namespace Ip6 {
 
-Icmp::Icmp(otInstance &aInstance):
+Icmp::Icmp(Instance &aInstance):
     InstanceLocator(aInstance),
     mHandlers(NULL),
     mEchoSequence(1),
diff --git a/src/core/net/icmp6.hpp b/src/core/net/icmp6.hpp
index dcfa05d..533f4f2 100644
--- a/src/core/net/icmp6.hpp
+++ b/src/core/net/icmp6.hpp
@@ -231,7 +231,7 @@
      * @param[in]  aInstance A reference to the OpenThread instance.
      *
      */
-    Icmp(otInstance &aInstance);
+    Icmp(Instance &aInstance);
 
     /**
      * This method returns a new ICMP message with sufficient header space reserved.
diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp
index 0cc0dd3..5672d99 100644
--- a/src/core/net/ip6.cpp
+++ b/src/core/net/ip6.cpp
@@ -35,9 +35,9 @@
 
 #include "ip6.hpp"
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/message.hpp"
 #include "net/icmp6.hpp"
@@ -50,7 +50,7 @@
 namespace ot {
 namespace Ip6 {
 
-Ip6::Ip6(otInstance &aInstance):
+Ip6::Ip6(Instance &aInstance):
     InstanceLocator(aInstance),
     mForwardingEnabled(false),
     mIsReceiveIp6FilterEnabled(false),
@@ -68,8 +68,8 @@
 
 Message *Ip6::NewMessage(uint16_t aReserved)
 {
-    return GetInstance().mMessagePool.New(Message::kTypeIp6,
-                                          sizeof(Header) + sizeof(HopByHopHeader) + sizeof(OptionMpl) + aReserved);
+    return GetInstance().GetMessagePool().New(Message::kTypeIp6,
+                                              sizeof(Header) + sizeof(HopByHopHeader) + sizeof(OptionMpl) + aReserved);
 }
 
 uint16_t Ip6::UpdateChecksum(uint16_t aChecksum, const Address &aAddress)
@@ -613,7 +613,7 @@
             case kCoapUdpPort:
 
                 // do not pass TMF messages
-                if (GetInstance().mThreadNetif.IsTmfMessage(aMessageInfo))
+                if (GetInstance().GetThreadNetif().IsTmfMessage(aMessageInfo))
                 {
                     ExitNow(error = OT_ERROR_NO_ROUTE);
                 }
@@ -1120,7 +1120,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     Ip6 &ip6 = *static_cast<Ip6 *>(aContext.GetContext());
 #else
-    Ip6 &ip6 = otGetIp6();
+    Ip6 &ip6 = Instance::Get().GetIp6();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return ip6;
diff --git a/src/core/net/ip6.hpp b/src/core/net/ip6.hpp
index 3b57b3f..b8a2662 100644
--- a/src/core/net/ip6.hpp
+++ b/src/core/net/ip6.hpp
@@ -123,7 +123,7 @@
      * @param[in]  aInstance   A reference to the otInstance object.
      *
      */
-    Ip6(otInstance &aInstance);
+    Ip6(Instance &aInstance);
 
     /**
      * This method sends an IPv6 datagram.
diff --git a/src/core/net/ip6_address.cpp b/src/core/net/ip6_address.cpp
index f3b744c..7796aa5 100644
--- a/src/core/net/ip6_address.cpp
+++ b/src/core/net/ip6_address.cpp
@@ -38,6 +38,7 @@
 
 #include "common/code_utils.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "mac/mac_frame.hpp"
 
 using ot::Encoding::BigEndian::HostSwap16;
diff --git a/src/core/net/ip6_filter.cpp b/src/core/net/ip6_filter.cpp
index 7bd43a5..c79a979 100644
--- a/src/core/net/ip6_filter.cpp
+++ b/src/core/net/ip6_filter.cpp
@@ -36,6 +36,7 @@
 #include <stdio.h>
 
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "net/ip6.hpp"
 #include "net/tcp.hpp"
 #include "net/udp6.hpp"
diff --git a/src/core/net/ip6_mpl.cpp b/src/core/net/ip6_mpl.cpp
index b146600..aef6fff 100644
--- a/src/core/net/ip6_mpl.cpp
+++ b/src/core/net/ip6_mpl.cpp
@@ -35,8 +35,8 @@
 
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "common/message.hpp"
 #include "net/ip6.hpp"
 
@@ -53,7 +53,7 @@
     SetIntervalOffset(aInterval - t);
 }
 
-Mpl::Mpl(otInstance &aInstance):
+Mpl::Mpl(Instance &aInstance):
     InstanceLocator(aInstance),
     mTimerExpirations(0),
     mSequence(0),
@@ -172,7 +172,7 @@
 #if OPENTHREAD_CONFIG_ENABLE_DYNAMIC_MPL_INTERVAL
     // adjust the first MPL forward interval dynamically according to the network scale
     uint8_t interval = (kDataMessageInterval / Mle::kMaxRouters) *
-                       GetInstance().mThreadNetif.GetMle().GetActiveNeighborRouterCount();
+                       GetInstance().GetThreadNetif().GetMle().GetActiveNeighborRouterCount();
 #else
     uint8_t interval = kDataMessageInterval;
 #endif
@@ -373,7 +373,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     Mpl &mpl = *static_cast<Mpl *>(aContext.GetContext());
 #else
-    Mpl &mpl = otGetIp6().GetMpl();
+    Mpl &mpl = Instance::Get().GetIp6().GetMpl();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return mpl;
diff --git a/src/core/net/ip6_mpl.hpp b/src/core/net/ip6_mpl.hpp
index 711f098..f9151ac 100644
--- a/src/core/net/ip6_mpl.hpp
+++ b/src/core/net/ip6_mpl.hpp
@@ -439,7 +439,7 @@
      * @param[in]  aInstance  A reference to the OpenThread instance.
      *
      */
-    Mpl(otInstance &aInstance);
+    Mpl(Instance &aInstance);
 
     /**
      * This method initializes the MPL option.
diff --git a/src/core/net/ip6_routes.cpp b/src/core/net/ip6_routes.cpp
index 8fd74c0..2739c46 100644
--- a/src/core/net/ip6_routes.cpp
+++ b/src/core/net/ip6_routes.cpp
@@ -34,6 +34,7 @@
 #include "ip6_routes.hpp"
 
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "common/message.hpp"
 #include "net/ip6.hpp"
 #include "net/netif.hpp"
@@ -41,7 +42,7 @@
 namespace ot {
 namespace Ip6 {
 
-Routes::Routes(otInstance &aInstance):
+Routes::Routes(Instance &aInstance):
     InstanceLocator(aInstance),
     mRoutes(NULL)
 {
diff --git a/src/core/net/ip6_routes.hpp b/src/core/net/ip6_routes.hpp
index 900e9c0..0a0b9e5 100644
--- a/src/core/net/ip6_routes.hpp
+++ b/src/core/net/ip6_routes.hpp
@@ -80,7 +80,7 @@
      * @param[in]  aInstance  A reference to the OpenThread instance.
      *
      */
-    Routes(otInstance &aInstance);
+    Routes(Instance &aInstance);
 
     /**
      * This method adds an IPv6 route.
diff --git a/src/core/net/netif.cpp b/src/core/net/netif.cpp
index ef444a9..54cc7a1 100644
--- a/src/core/net/netif.cpp
+++ b/src/core/net/netif.cpp
@@ -33,9 +33,9 @@
 
 #include "netif.hpp"
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/message.hpp"
 #include "net/ip6.hpp"
 
@@ -90,7 +90,7 @@
 };
 
 
-Netif::Netif(otInstance &aInstance, int8_t aInterfaceId):
+Netif::Netif(Instance &aInstance, int8_t aInterfaceId):
     InstanceLocator(aInstance),
     mCallbacks(NULL),
     mUnicastAddresses(NULL),
@@ -581,7 +581,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     Netif &netif = *static_cast<Netif *>(aContext.GetContext());
 #else
-    Netif &netif = otGetThreadNetif();
+    Netif &netif = Instance::Get().GetThreadNetif();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return netif;
diff --git a/src/core/net/netif.hpp b/src/core/net/netif.hpp
index 9835a22..aff1854 100644
--- a/src/core/net/netif.hpp
+++ b/src/core/net/netif.hpp
@@ -264,7 +264,7 @@
      * @param[in]  aInterfaceId     The interface ID for this object.
      *
      */
-    Netif(otInstance &aInstance, int8_t aInterfaceId);
+    Netif(Instance &aInstance, int8_t aInterfaceId);
 
     /**
      * This method returns the next network interface in the list.
diff --git a/src/core/net/udp6.cpp b/src/core/net/udp6.cpp
index 49ae56d..dc8a103 100644
--- a/src/core/net/udp6.cpp
+++ b/src/core/net/udp6.cpp
@@ -37,6 +37,7 @@
 
 #include "common/code_utils.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "net/ip6.hpp"
 
 using ot::Encoding::BigEndian::HostSwap16;
@@ -138,7 +139,7 @@
     return error;
 }
 
-Udp::Udp(otInstance &aInstance):
+Udp::Udp(Instance &aInstance):
     InstanceLocator(aInstance),
     mEphemeralPort(kDynamicPortMin),
     mSockets(NULL)
diff --git a/src/core/net/udp6.hpp b/src/core/net/udp6.hpp
index 310b262..1a1cfb6 100644
--- a/src/core/net/udp6.hpp
+++ b/src/core/net/udp6.hpp
@@ -175,7 +175,7 @@
      * @param[in]  aIp6  A reference to OpenThread instance.
      *
      */
-    Udp(otInstance &aInstance);
+    Udp(Instance &aInstance);
 
     /**
      * This method adds a UDP socket.
diff --git a/src/core/openthread-instance.h b/src/core/openthread-instance.h
deleted file mode 100644
index 0768bb9..0000000
--- a/src/core/openthread-instance.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- *  Copyright (c) 2016, The OpenThread Authors.
- *  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 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 the copyright holder nor the
- *     names of its contributors may be used to endorse or promote products
- *     derived from this software without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
- */
-
-/**
- * @file
- * @brief
- *  This file defines the structure of the variables required for all instances of OpenThread API.
- */
-
-#ifndef OPENTHREADINSTANCE_H_
-#define OPENTHREADINSTANCE_H_
-
-#include "openthread-core-config.h"
-
-#include "utils/wrap_stdint.h"
-#include "utils/wrap_stdbool.h"
-
-#include <openthread/types.h>
-#include <openthread/platform/logging.h>
-
-#include "openthread-single-instance.h"
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-#include "api/link_raw.hpp"
-#endif
-#include "coap/coap.hpp"
-#include "crypto/heap.hpp"
-#include "crypto/mbedtls.hpp"
-#include "net/ip6.hpp"
-#include "thread/thread_netif.hpp"
-
-/**
- * This type represents all the static / global variables used by OpenThread allocated in one place.
- */
-typedef struct otInstance
-{
-    //
-    // Callbacks
-    //
-
-    ot::Ip6::NetifCallback mNetifCallback[OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS];
-
-    otIp6ReceiveCallback mReceiveIp6DatagramCallback;
-    void *mReceiveIp6DatagramCallbackContext;
-
-    otHandleActiveScanResult mActiveScanCallback;
-    void *mActiveScanCallbackContext;
-
-    otHandleEnergyScanResult mEnergyScanCallback;
-    void *mEnergyScanCallbackContext;
-
-    //
-    // State
-    //
-
-    ot::TaskletScheduler mTaskletScheduler;
-    ot::TimerMilliScheduler mTimerMilliScheduler;
-#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
-    ot::TimerMicroScheduler mTimerMicroScheduler;
-#endif
-
-#if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
-    ot::Crypto::MbedTls mMbedTls;
-    ot::Crypto::Heap    mMbedTlsHeap;
-#endif
-    ot::Ip6::Ip6 mIp6;
-    ot::ThreadNetif mThreadNetif;
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-    ot::LinkRaw mLinkRaw;
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
-
-#if OPENTHREAD_ENABLE_APPLICATION_COAP
-    ot::Coap::ApplicationCoap mApplicationCoap;
-#endif // OPENTHREAD_ENABLE_APPLICATION_COAP
-
-#if OPENTHREAD_CONFIG_ENABLE_DYNAMIC_LOG_LEVEL
-    otLogLevel mLogLevel;
-#endif // OPENTHREAD_CONFIG_ENABLE_DYNAMIC_LOG_LEVEL
-    ot::MessagePool mMessagePool;
-
-    // Constructor
-    otInstance(void);
-
-} otInstance;
-
-#endif  // OPENTHREADINSTANCE_H_
diff --git a/src/core/openthread-single-instance.h b/src/core/openthread-single-instance.h
deleted file mode 100644
index 42f455b..0000000
--- a/src/core/openthread-single-instance.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- *  Copyright (c) 2017, The OpenThread Authors.
- *  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 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 the copyright holder nor the
- *     names of its contributors may be used to endorse or promote products
- *     derived from this software without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
- */
-
-/**
- * @file
- * @brief
- *  This file defines the getter functions for single instance OpenThread objects.
- */
-
-#ifndef SINGLE_OPENTHREAD_INSTANCE_H_
-#define SINGLE_OPENTHREAD_INSTANCE_H_
-
-#include "openthread-core-config.h"
-
-#include <openthread/types.h>
-
-
-#if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
-
-namespace ot {
-
-class ThreadNetif;
-class MeshForwarder;
-class TaskletScheduler;
-namespace Ip6 { class Ip6; }
-
-} // namespace ot
-
-/**
- * This function returns a pointer to the single otInstance (if initialized and ready).
- *
- * @returns A pointer to single otInstance structure, or NULL if the instance is not ready, i.e. either it is not yet
- *          initialized (no call to `otInstanceInitSingle()`) or it is finalized (call to `otInstanceFinalize()`).
- *
- */
-otInstance *otGetInstance(void);
-
-/**
- * This function returns a reference to the single thread network interface instance.
- *
- * @returns A reference to the thread network interface instance.
- *
- */
-ot::ThreadNetif &otGetThreadNetif(void);
-
-/**
- * This function returns a reference to the single MeshForwarder instance.
- *
- * @returns A reference to the MeshForwarder instance.
- *
- */
-ot::MeshForwarder &otGetMeshForwarder(void);
-
-/**
- * This function returns a reference to the single TaskletShceduler instance.
- *
- * @returns A reference to the TaskletShceduler instance.
- *
- */
-ot::TaskletScheduler &otGetTaskletScheduler(void);
-
-/**
- * This function returns a reference to the single Ip6 instance.
- *
- * @returns A reference to the Ip6 instance.
- *
- */
-ot::Ip6::Ip6 &otGetIp6(void);
-
-#endif // #if !OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
-
-#endif  // SINGLE_OPENTHREAD_INSTANCE_H_
diff --git a/src/core/thread/address_resolver.cpp b/src/core/thread/address_resolver.cpp
index fe31e2a..6db9c50 100644
--- a/src/core/thread/address_resolver.cpp
+++ b/src/core/thread/address_resolver.cpp
@@ -39,11 +39,11 @@
 
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "coap/coap_header.hpp"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "mac/mac_frame.hpp"
 #include "thread/mesh_forwarder.hpp"
@@ -56,7 +56,7 @@
 
 namespace ot {
 
-AddressResolver::AddressResolver(otInstance &aInstance) :
+AddressResolver::AddressResolver(Instance &aInstance) :
     InstanceLocator(aInstance),
     mAddressError(OT_URI_PATH_ADDRESS_ERROR, &AddressResolver::HandleAddressError, this),
     mAddressQuery(OT_URI_PATH_ADDRESS_QUERY, &AddressResolver::HandleAddressQuery, this),
@@ -814,7 +814,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     AddressResolver &resolver = *static_cast<AddressResolver *>(aContext.GetContext());
 #else
-    AddressResolver &resolver = otGetThreadNetif().GetAddressResolver();
+    AddressResolver &resolver = Instance::Get().GetThreadNetif().GetAddressResolver();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return resolver;
diff --git a/src/core/thread/address_resolver.hpp b/src/core/thread/address_resolver.hpp
index 0892c34..fcb7aa9 100644
--- a/src/core/thread/address_resolver.hpp
+++ b/src/core/thread/address_resolver.hpp
@@ -73,7 +73,7 @@
      * This constructor initializes the object.
      *
      */
-    explicit AddressResolver(otInstance &aInstance);
+    explicit AddressResolver(Instance &aInstance);
 
     /**
      * This method clears the EID-to-RLOC cache.
diff --git a/src/core/thread/announce_begin_server.cpp b/src/core/thread/announce_begin_server.cpp
index 1fb008b..c52120b 100644
--- a/src/core/thread/announce_begin_server.cpp
+++ b/src/core/thread/announce_begin_server.cpp
@@ -37,9 +37,9 @@
 
 #include <openthread/platform/radio.h>
 
-#include "openthread-instance.h"
 #include "coap/coap_header.hpp"
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "common/debug.hpp"
 #include "common/logging.hpp"
 #include "meshcop/meshcop_tlvs.hpp"
@@ -50,7 +50,7 @@
 
 namespace ot {
 
-AnnounceBeginServer::AnnounceBeginServer(otInstance &aInstance) :
+AnnounceBeginServer::AnnounceBeginServer(Instance &aInstance) :
     InstanceLocator(aInstance),
     mChannelMask(0),
     mPeriod(0),
@@ -157,7 +157,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     AnnounceBeginServer &server = *static_cast<AnnounceBeginServer *>(aContext.GetContext());
 #else
-    AnnounceBeginServer &server = otGetThreadNetif().GetAnnounceBeginServer();
+    AnnounceBeginServer &server = Instance::Get().GetThreadNetif().GetAnnounceBeginServer();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return server;
diff --git a/src/core/thread/announce_begin_server.hpp b/src/core/thread/announce_begin_server.hpp
index 201b02c..7ee1ed7 100644
--- a/src/core/thread/announce_begin_server.hpp
+++ b/src/core/thread/announce_begin_server.hpp
@@ -56,7 +56,7 @@
      * This constructor initializes the object.
      *
      */
-    AnnounceBeginServer(otInstance &aInstance);
+    AnnounceBeginServer(Instance &aInstance);
 
     /**
      * This method begins the MLE Announce transmission process using Count=3 and Period=1s.
diff --git a/src/core/thread/data_poll_manager.cpp b/src/core/thread/data_poll_manager.cpp
index 213d5dc..26aea42 100644
--- a/src/core/thread/data_poll_manager.cpp
+++ b/src/core/thread/data_poll_manager.cpp
@@ -37,8 +37,8 @@
 
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/message.hpp"
 #include "net/ip6.hpp"
@@ -49,7 +49,7 @@
 
 namespace ot {
 
-DataPollManager::DataPollManager(otInstance &aInstance):
+DataPollManager::DataPollManager(Instance &aInstance):
     InstanceLocator(aInstance),
     mTimerStartTime(0),
     mExternalPollPeriod(0),
@@ -112,7 +112,7 @@
         VerifyOrExit(message->GetType() != Message::kTypeMacDataPoll, error = OT_ERROR_ALREADY);
     }
 
-    message = GetInstance().mMessagePool.New(Message::kTypeMacDataPoll, 0);
+    message = GetInstance().GetMessagePool().New(Message::kTypeMacDataPoll, 0);
     VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
 
     error = netif.GetMeshForwarder().SendMessage(*message);
@@ -418,7 +418,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     DataPollManager &manager = *static_cast<DataPollManager *>(aContext.GetContext());
 #else
-    DataPollManager &manager = otGetMeshForwarder().GetDataPollManager();
+    DataPollManager &manager = Instance::Get().GetThreadNetif().GetMeshForwarder().GetDataPollManager();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return manager;
diff --git a/src/core/thread/data_poll_manager.hpp b/src/core/thread/data_poll_manager.hpp
index 3731a85..b6ab9bf 100644
--- a/src/core/thread/data_poll_manager.hpp
+++ b/src/core/thread/data_poll_manager.hpp
@@ -74,7 +74,7 @@
      * @param[in]  aInstance   A reference to the OpenThread instance.
      *
      */
-    explicit DataPollManager(otInstance &aInstance);
+    explicit DataPollManager(Instance &aInstance);
 
     /**
      * This method instructs the data poll manager to start sending periodic data polls.
diff --git a/src/core/thread/energy_scan_server.cpp b/src/core/thread/energy_scan_server.cpp
index b0702c9..fdb4223 100644
--- a/src/core/thread/energy_scan_server.cpp
+++ b/src/core/thread/energy_scan_server.cpp
@@ -37,10 +37,10 @@
 
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "coap/coap_header.hpp"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "meshcop/meshcop.hpp"
 #include "meshcop/meshcop_tlvs.hpp"
@@ -49,7 +49,7 @@
 
 namespace ot {
 
-EnergyScanServer::EnergyScanServer(otInstance &aInstance) :
+EnergyScanServer::EnergyScanServer(Instance &aInstance) :
     InstanceLocator(aInstance),
     mChannelMask(0),
     mChannelMaskCurrent(0),
@@ -246,7 +246,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     EnergyScanServer &server = *static_cast<EnergyScanServer *>(aContext.GetContext());
 #else
-    EnergyScanServer &server = otGetThreadNetif().GetEnergyScanServer();
+    EnergyScanServer &server = Instance::Get().GetThreadNetif().GetEnergyScanServer();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return server;
diff --git a/src/core/thread/energy_scan_server.hpp b/src/core/thread/energy_scan_server.hpp
index 0b10e6e..19f841d 100644
--- a/src/core/thread/energy_scan_server.hpp
+++ b/src/core/thread/energy_scan_server.hpp
@@ -63,7 +63,7 @@
      * This constructor initializes the object.
      *
      */
-    EnergyScanServer(otInstance &aInstance);
+    EnergyScanServer(Instance &aInstance);
 
 private:
     enum
diff --git a/src/core/thread/key_manager.cpp b/src/core/thread/key_manager.cpp
index e76dc18..1609d22 100644
--- a/src/core/thread/key_manager.cpp
+++ b/src/core/thread/key_manager.cpp
@@ -33,8 +33,8 @@
 
 #include "key_manager.hpp"
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "common/timer.hpp"
 #include "crypto/hmac_sha256.hpp"
 #include "thread/mle_router.hpp"
@@ -47,7 +47,7 @@
     'T', 'h', 'r', 'e', 'a', 'd',
 };
 
-KeyManager::KeyManager(otInstance &aInstance):
+KeyManager::KeyManager(Instance &aInstance):
     InstanceLocator(aInstance),
     mKeySequence(0),
     mMacFrameCounter(0),
@@ -275,7 +275,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     KeyManager &keyManager = *static_cast<KeyManager *>(aContext.GetContext());
 #else
-    KeyManager &keyManager = otGetThreadNetif().GetKeyManager();
+    KeyManager &keyManager = Instance::Get().GetThreadNetif().GetKeyManager();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return keyManager;
diff --git a/src/core/thread/key_manager.hpp b/src/core/thread/key_manager.hpp
index 198dab7..c046ee5 100644
--- a/src/core/thread/key_manager.hpp
+++ b/src/core/thread/key_manager.hpp
@@ -69,7 +69,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    explicit KeyManager(otInstance &aInstance);
+    explicit KeyManager(Instance &aInstance);
 
     /**
      * This method starts KeyManager rotation timer and sets guard timer to initial value.
diff --git a/src/core/thread/link_quality.cpp b/src/core/thread/link_quality.cpp
index 4d20e02..90928d6 100644
--- a/src/core/thread/link_quality.cpp
+++ b/src/core/thread/link_quality.cpp
@@ -36,6 +36,7 @@
 #include <stdio.h>
 
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "utils/wrap_string.h"
 
 namespace ot {
diff --git a/src/core/thread/lowpan.cpp b/src/core/thread/lowpan.cpp
index aa7f702..025d3b1 100644
--- a/src/core/thread/lowpan.cpp
+++ b/src/core/thread/lowpan.cpp
@@ -36,6 +36,7 @@
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "net/ip6.hpp"
 #include "net/udp6.hpp"
 #include "thread/network_data_leader.hpp"
@@ -46,7 +47,7 @@
 namespace ot {
 namespace Lowpan {
 
-Lowpan::Lowpan(otInstance &aInstance):
+Lowpan::Lowpan(Instance &aInstance):
     InstanceLocator(aInstance)
 {
 }
diff --git a/src/core/thread/lowpan.hpp b/src/core/thread/lowpan.hpp
index f3dae69..48e074e 100644
--- a/src/core/thread/lowpan.hpp
+++ b/src/core/thread/lowpan.hpp
@@ -87,7 +87,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    explicit Lowpan(otInstance &aInstance);
+    explicit Lowpan(Instance &aInstance);
 
     /**
      * This method indicates whether or not the header is a LOWPAN_IPHC header.
diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp
index 16ce3ac..1f35be5 100644
--- a/src/core/thread/mesh_forwarder.cpp
+++ b/src/core/thread/mesh_forwarder.cpp
@@ -37,10 +37,10 @@
 
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/message.hpp"
 #include "net/ip6.hpp"
@@ -56,7 +56,7 @@
 
 namespace ot {
 
-MeshForwarder::MeshForwarder(otInstance &aInstance):
+MeshForwarder::MeshForwarder(Instance &aInstance):
     InstanceLocator(aInstance),
     mMacReceiver(&MeshForwarder::HandleReceivedFrame, &MeshForwarder::HandleDataPollTimeout, this),
     mMacSender(&MeshForwarder::HandleFrameRequest, &MeshForwarder::HandleSentFrame, this),
@@ -2011,7 +2011,7 @@
         meshHeader.SetHopsLeft(meshHeader.GetHopsLeft() - 1);
         meshHeader.AppendTo(aFrame);
 
-        VerifyOrExit((message = GetInstance().mMessagePool.New(Message::kType6lowpan, 0)) != NULL,
+        VerifyOrExit((message = GetInstance().GetMessagePool().New(Message::kType6lowpan, 0)) != NULL,
                      error = OT_ERROR_NO_BUFS);
         SuccessOrExit(error = message->SetLength(aFrameLength));
         message->Write(0, aFrameLength, aFrame);
@@ -2145,7 +2145,7 @@
 
     if (fragmentHeader.GetDatagramOffset() == 0)
     {
-        VerifyOrExit((message = GetInstance().mMessagePool.New(Message::kTypeIp6, 0)) != NULL,
+        VerifyOrExit((message = GetInstance().GetMessagePool().New(Message::kTypeIp6, 0)) != NULL,
                      error = OT_ERROR_NO_BUFS);
         message->SetLinkSecurityEnabled(aLinkInfo.mLinkSecurity);
         message->SetPanId(aLinkInfo.mPanId);
@@ -2324,7 +2324,7 @@
     Message *message;
     int headerLength;
 
-    VerifyOrExit((message = GetInstance().mMessagePool.New(Message::kTypeIp6, 0)) != NULL,
+    VerifyOrExit((message = GetInstance().GetMessagePool().New(Message::kTypeIp6, 0)) != NULL,
                  error = OT_ERROR_NO_BUFS);
     message->SetLinkSecurityEnabled(aLinkInfo.mLinkSecurity);
     message->SetPanId(aLinkInfo.mPanId);
@@ -2424,7 +2424,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     MeshForwarder &meshForwader = *static_cast<MeshForwarder *>(aContext.GetContext());
 #else
-    MeshForwarder &meshForwader = otGetMeshForwarder();
+    MeshForwarder &meshForwader = Instance::Get().GetThreadNetif().GetMeshForwarder();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return meshForwader;
diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp
index f457572..3862494 100644
--- a/src/core/thread/mesh_forwarder.hpp
+++ b/src/core/thread/mesh_forwarder.hpp
@@ -80,7 +80,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    explicit MeshForwarder(otInstance &aInstance);
+    explicit MeshForwarder(Instance &aInstance);
 
     /**
      * This method enables mesh forwarding and the IEEE 802.15.4 MAC layer.
diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp
index 71f8948..332e30a 100644
--- a/src/core/thread/mle.cpp
+++ b/src/core/thread/mle.cpp
@@ -39,10 +39,10 @@
 #include <openthread/platform/random.h>
 #include <openthread/platform/settings.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/settings.hpp"
 #include "crypto/aes_ccm.hpp"
@@ -60,7 +60,7 @@
 namespace ot {
 namespace Mle {
 
-Mle::Mle(otInstance &aInstance) :
+Mle::Mle(Instance &aInstance) :
     InstanceLocator(aInstance),
     mRetrieveNewNetworkData(false),
     mRole(OT_DEVICE_ROLE_DISABLED),
@@ -82,7 +82,7 @@
     mChildUpdateAttempts(0),
     mParentLinkMargin(0),
     mParentIsSingleton(false),
-    mSocket(aInstance.mThreadNetif.GetIp6().GetUdp()),
+    mSocket(aInstance.GetThreadNetif().GetIp6().GetUdp()),
     mTimeout(kMleEndDeviceTimeout),
     mSendChildUpdateRequest(aInstance, &Mle::HandleSendChildUpdateRequest, this),
     mDiscoverHandler(NULL),
@@ -3438,7 +3438,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     Mle &mle = *static_cast<Mle *>(aContext.GetContext());
 #else
-    Mle &mle = otGetInstance()->mThreadNetif.GetMle();
+    Mle &mle = Instance::Get().GetThreadNetif().GetMle();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return mle;
diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp
index 5a8e851..7c3bb06 100644
--- a/src/core/thread/mle.hpp
+++ b/src/core/thread/mle.hpp
@@ -468,7 +468,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    explicit Mle(otInstance &aInstance);
+    explicit Mle(Instance &aInstance);
 
     /**
      * This method enables MLE.
diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp
index ce85dde..2f94710 100644
--- a/src/core/thread/mle_router.cpp
+++ b/src/core/thread/mle_router.cpp
@@ -39,10 +39,10 @@
 #include <openthread/platform/random.h>
 #include <openthread/platform/settings.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/settings.hpp"
 #include "mac/mac_frame.hpp"
@@ -56,7 +56,7 @@
 namespace ot {
 namespace Mle {
 
-MleRouter::MleRouter(otInstance &aInstance):
+MleRouter::MleRouter(Instance &aInstance):
     Mle(aInstance),
     mAdvertiseTimer(aInstance, &MleRouter::HandleAdvertiseTimer, NULL, this),
     mStateUpdateTimer(aInstance, &MleRouter::HandleStateUpdateTimer, this),
@@ -4845,7 +4845,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     MleRouter &mle = *static_cast<MleRouter *>(aContext.GetContext());
 #else
-    MleRouter &mle = otGetThreadNetif().GetMle();
+    MleRouter &mle = Instance::Get().GetThreadNetif().GetMle();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return mle;
diff --git a/src/core/thread/mle_router_ftd.hpp b/src/core/thread/mle_router_ftd.hpp
index b1551b3..ce8ad9a 100644
--- a/src/core/thread/mle_router_ftd.hpp
+++ b/src/core/thread/mle_router_ftd.hpp
@@ -84,7 +84,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    explicit MleRouter(otInstance &aInstance);
+    explicit MleRouter(Instance &aInstance);
 
     /**
      * This method indicates whether or not the Router Role is enabled.
diff --git a/src/core/thread/mle_router_mtd.hpp b/src/core/thread/mle_router_mtd.hpp
index 488ba15..c5fc568 100644
--- a/src/core/thread/mle_router_mtd.hpp
+++ b/src/core/thread/mle_router_mtd.hpp
@@ -50,7 +50,7 @@
     friend class Mle;
 
 public:
-    explicit MleRouter(otInstance &aInstance) : Mle(aInstance) { }
+    explicit MleRouter(Instance &aInstance) : Mle(aInstance) { }
 
     bool IsSingleton(void) { return false; }
 
diff --git a/src/core/thread/network_data.cpp b/src/core/thread/network_data.cpp
index 9dd34c5..3d2f367 100644
--- a/src/core/thread/network_data.cpp
+++ b/src/core/thread/network_data.cpp
@@ -40,6 +40,7 @@
 #include "coap/coap_header.hpp"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "mac/mac_frame.hpp"
 #include "thread/thread_netif.hpp"
@@ -49,7 +50,7 @@
 namespace ot {
 namespace NetworkData {
 
-NetworkData::NetworkData(otInstance &aInstance, bool aLocal):
+NetworkData::NetworkData(Instance &aInstance, bool aLocal):
     InstanceLocator(aInstance),
     mLocal(aLocal),
     mLastAttemptWait(false),
diff --git a/src/core/thread/network_data.hpp b/src/core/thread/network_data.hpp
index cf3c044..b8ce019 100644
--- a/src/core/thread/network_data.hpp
+++ b/src/core/thread/network_data.hpp
@@ -101,7 +101,7 @@
      * @param[in]  aLocal        TRUE if this represents local network data, FALSE otherwise.
      *
      */
-    NetworkData(otInstance &aInstance, bool aLocal);
+    NetworkData(Instance &aInstance, bool aLocal);
 
     /**
      * This method clears the network data.
diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp
index a247c5d..ed229f7 100644
--- a/src/core/thread/network_data_leader.cpp
+++ b/src/core/thread/network_data_leader.cpp
@@ -41,6 +41,7 @@
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/message.hpp"
 #include "common/timer.hpp"
@@ -56,7 +57,7 @@
 namespace ot {
 namespace NetworkData {
 
-LeaderBase::LeaderBase(otInstance &aInstance):
+LeaderBase::LeaderBase(Instance &aInstance):
     NetworkData(aInstance, false)
 {
     Reset();
diff --git a/src/core/thread/network_data_leader.hpp b/src/core/thread/network_data_leader.hpp
index 47a969c..4d41b79 100644
--- a/src/core/thread/network_data_leader.hpp
+++ b/src/core/thread/network_data_leader.hpp
@@ -73,7 +73,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    explicit LeaderBase(otInstance &aInstance);
+    explicit LeaderBase(Instance &aInstance);
 
     /**
      * This method reset the Thread Network Data.
diff --git a/src/core/thread/network_data_leader_ftd.cpp b/src/core/thread/network_data_leader_ftd.cpp
index 1f8370b..f3368ee 100644
--- a/src/core/thread/network_data_leader_ftd.cpp
+++ b/src/core/thread/network_data_leader_ftd.cpp
@@ -40,11 +40,11 @@
 
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "coap/coap_header.hpp"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/message.hpp"
 #include "common/timer.hpp"
@@ -61,7 +61,7 @@
 namespace ot {
 namespace NetworkData {
 
-Leader::Leader(otInstance &aInstance):
+Leader::Leader(Instance &aInstance):
     LeaderBase(aInstance),
     mTimer(aInstance, &Leader::HandleTimer, this),
     mServerData(OT_URI_PATH_SERVER_DATA, &Leader::HandleServerData, this),
@@ -1551,7 +1551,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     Leader &leader = *static_cast<Leader *>(aContext.GetContext());
 #else
-    Leader &leader = otGetThreadNetif().GetNetworkDataLeader();
+    Leader &leader = Instance::Get().GetThreadNetif().GetNetworkDataLeader();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return leader;
diff --git a/src/core/thread/network_data_leader_ftd.hpp b/src/core/thread/network_data_leader_ftd.hpp
index c530fc0..66cf389 100644
--- a/src/core/thread/network_data_leader_ftd.hpp
+++ b/src/core/thread/network_data_leader_ftd.hpp
@@ -73,7 +73,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    explicit Leader(otInstance &aInstance);
+    explicit Leader(Instance &aInstance);
 
     /**
      * This method reset the Thread Network Data.
diff --git a/src/core/thread/network_data_leader_mtd.hpp b/src/core/thread/network_data_leader_mtd.hpp
index 27df60c..3fae524 100644
--- a/src/core/thread/network_data_leader_mtd.hpp
+++ b/src/core/thread/network_data_leader_mtd.hpp
@@ -47,7 +47,7 @@
 class Leader: public LeaderBase
 {
 public:
-    explicit Leader(otInstance &aInstance) : LeaderBase(aInstance) { }
+    explicit Leader(Instance &aInstance) : LeaderBase(aInstance) { }
 
     void Start(void) { }
     void Stop(void) { }
diff --git a/src/core/thread/network_data_local.cpp b/src/core/thread/network_data_local.cpp
index cf583d9..0b9dc6c 100644
--- a/src/core/thread/network_data_local.cpp
+++ b/src/core/thread/network_data_local.cpp
@@ -33,9 +33,10 @@
 
 #include "network_data_local.hpp"
 
-#include "common/debug.hpp"
-#include "common/logging.hpp"
 #include "common/code_utils.hpp"
+#include "common/debug.hpp"
+#include "common/instance.hpp"
+#include "common/logging.hpp"
 #include "mac/mac_frame.hpp"
 #include "thread/thread_netif.hpp"
 
@@ -44,7 +45,7 @@
 namespace ot {
 namespace NetworkData {
 
-Local::Local(otInstance &aInstance):
+Local::Local(Instance &aInstance):
     NetworkData(aInstance, true),
     mOldRloc(Mac::kShortAddrInvalid)
 {
diff --git a/src/core/thread/network_data_local.hpp b/src/core/thread/network_data_local.hpp
index 37c86ee..f50499a 100644
--- a/src/core/thread/network_data_local.hpp
+++ b/src/core/thread/network_data_local.hpp
@@ -66,7 +66,7 @@
      * @param[in]  aNetif  A reference to the Thread network interface.
      *
      */
-    explicit Local(otInstance &aInstance);
+    explicit Local(Instance &aInstance);
 
     /**
      * This method adds a Border Router entry to the Thread Network Data.
diff --git a/src/core/thread/network_diagnostic.cpp b/src/core/thread/network_diagnostic.cpp
index 17ff06c..513344e 100644
--- a/src/core/thread/network_diagnostic.cpp
+++ b/src/core/thread/network_diagnostic.cpp
@@ -40,6 +40,7 @@
 #include "coap/coap_header.hpp"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "common/encoding.hpp"
 #include "mac/mac_frame.hpp"
@@ -59,7 +60,7 @@
 
 namespace NetworkDiagnostic {
 
-NetworkDiagnostic::NetworkDiagnostic(otInstance &aInstance) :
+NetworkDiagnostic::NetworkDiagnostic(Instance &aInstance) :
     InstanceLocator(aInstance),
     mDiagnosticGetRequest(OT_URI_PATH_DIAGNOSTIC_GET_REQUEST, &NetworkDiagnostic::HandleDiagnosticGetRequest, this),
     mDiagnosticGetQuery(OT_URI_PATH_DIAGNOSTIC_GET_QUERY, &NetworkDiagnostic::HandleDiagnosticGetQuery, this),
diff --git a/src/core/thread/network_diagnostic.hpp b/src/core/thread/network_diagnostic.hpp
index ec1dfeb..3e6f1d7 100644
--- a/src/core/thread/network_diagnostic.hpp
+++ b/src/core/thread/network_diagnostic.hpp
@@ -70,7 +70,7 @@
      * This constructor initializes the object.
      *
      */
-    explicit NetworkDiagnostic(otInstance &aInstance);
+    explicit NetworkDiagnostic(Instance &aInstance);
 
     /**
      * This method registers a callback to provide received raw DIAG_GET.rsp or an DIAG_GET.ans payload.
diff --git a/src/core/thread/panid_query_server.cpp b/src/core/thread/panid_query_server.cpp
index 7a45087..811b30b 100644
--- a/src/core/thread/panid_query_server.cpp
+++ b/src/core/thread/panid_query_server.cpp
@@ -37,10 +37,10 @@
 
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "coap/coap_header.hpp"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "meshcop/meshcop.hpp"
 #include "meshcop/meshcop_tlvs.hpp"
@@ -49,7 +49,7 @@
 
 namespace ot {
 
-PanIdQueryServer::PanIdQueryServer(otInstance &aInstance) :
+PanIdQueryServer::PanIdQueryServer(Instance &aInstance) :
     InstanceLocator(aInstance),
     mChannelMask(0),
     mPanId(Mac::kPanIdBroadcast),
@@ -178,7 +178,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     PanIdQueryServer &server = *static_cast<PanIdQueryServer *>(aContext.GetContext());
 #else
-    PanIdQueryServer &server = otGetThreadNetif().GetPanIdQueryServer();
+    PanIdQueryServer &server = Instance::Get().GetThreadNetif().GetPanIdQueryServer();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return server;
diff --git a/src/core/thread/panid_query_server.hpp b/src/core/thread/panid_query_server.hpp
index cfdb182..02fb0b7 100644
--- a/src/core/thread/panid_query_server.hpp
+++ b/src/core/thread/panid_query_server.hpp
@@ -63,7 +63,7 @@
      * This constructor initializes the object.
      *
      */
-    PanIdQueryServer(otInstance &aInstance);
+    PanIdQueryServer(Instance &aInstance);
 
 private:
     enum
diff --git a/src/core/thread/src_match_controller.cpp b/src/core/thread/src_match_controller.cpp
index a715315..f9fa9eb 100644
--- a/src/core/thread/src_match_controller.cpp
+++ b/src/core/thread/src_match_controller.cpp
@@ -37,13 +37,14 @@
 
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "thread/mesh_forwarder.hpp"
 #include "thread/thread_netif.hpp"
 
 namespace ot {
 
-SourceMatchController::SourceMatchController(otInstance &aInstance) :
+SourceMatchController::SourceMatchController(Instance &aInstance) :
     InstanceLocator(aInstance),
     mEnabled(false)
 {
diff --git a/src/core/thread/src_match_controller.hpp b/src/core/thread/src_match_controller.hpp
index 86aa469..45d44fe 100644
--- a/src/core/thread/src_match_controller.hpp
+++ b/src/core/thread/src_match_controller.hpp
@@ -74,7 +74,7 @@
      * @param[in]  aInstance    A reference to the OpenThread instance
      *
      */
-    explicit SourceMatchController(otInstance &aInstance);
+    explicit SourceMatchController(Instance &aInstance);
 
     /**
      * This method returns the current state of source address matching.
diff --git a/src/core/thread/thread_netif.cpp b/src/core/thread/thread_netif.cpp
index 7d83690..2a859ac 100644
--- a/src/core/thread/thread_netif.cpp
+++ b/src/core/thread/thread_netif.cpp
@@ -34,9 +34,9 @@
 
 #include "thread_netif.hpp"
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/encoding.hpp"
+#include "common/instance.hpp"
 #include "common/message.hpp"
 #include "net/ip6.hpp"
 #include "net/netif.hpp"
@@ -57,7 +57,7 @@
     }
 };
 
-ThreadNetif::ThreadNetif(otInstance &aInstance):
+ThreadNetif::ThreadNetif(Instance &aInstance):
     Netif(aInstance, OT_NETIF_INTERFACE_ID_THREAD),
     mCoap(aInstance),
 #if OPENTHREAD_ENABLE_DHCP6_CLIENT
@@ -67,7 +67,7 @@
     mDhcp6Server(aInstance),
 #endif  // OPENTHREAD_ENABLE_DHCP6_SERVER
 #if OPENTHREAD_ENABLE_DNS_CLIENT
-    mDnsClient(aInstance.mThreadNetif),
+    mDnsClient(aInstance.GetThreadNetif()),
 #endif  // OPENTHREAD_ENABLE_DNS_CLIENT
     mActiveDataset(aInstance),
     mPendingDataset(aInstance),
diff --git a/src/core/thread/thread_netif.hpp b/src/core/thread/thread_netif.hpp
index f725e3c..325c998 100644
--- a/src/core/thread/thread_netif.hpp
+++ b/src/core/thread/thread_netif.hpp
@@ -104,7 +104,7 @@
      * @param[in]  aInstance  A reference to the OpenThread instance.
      *
      */
-    ThreadNetif(otInstance &aInstance);
+    ThreadNetif(Instance &aInstance);
 
     /**
      * This method enables the Thread network interface.
diff --git a/src/core/thread/tmf_proxy.cpp b/src/core/thread/tmf_proxy.cpp
index 31053ee..955f58b 100644
--- a/src/core/thread/tmf_proxy.cpp
+++ b/src/core/thread/tmf_proxy.cpp
@@ -37,6 +37,7 @@
 
 #include <openthread/types.h>
 
+#include "common/instance.hpp"
 #include "coap/coap_header.hpp"
 #include "net/ip6_address.hpp"
 #include "thread/thread_tlvs.hpp"
diff --git a/src/core/utils/child_supervision.cpp b/src/core/utils/child_supervision.cpp
index 3e25fcd..232aac7 100644
--- a/src/core/utils/child_supervision.cpp
+++ b/src/core/utils/child_supervision.cpp
@@ -36,8 +36,8 @@
 #include <openthread/openthread.h>
 
 #include "openthread-core-config.h"
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "common/logging.hpp"
 #include "thread/thread_netif.hpp"
 
@@ -48,7 +48,7 @@
 
 #if OPENTHREAD_FTD
 
-ChildSupervisor::ChildSupervisor(otInstance &aInstance) :
+ChildSupervisor::ChildSupervisor(Instance &aInstance) :
     InstanceLocator(aInstance),
     mSupervisionInterval(kDefaultSupervisionInterval),
     mTimer(aInstance, &ChildSupervisor::HandleTimer, this)
@@ -101,7 +101,7 @@
 
     VerifyOrExit(aChild.GetIndirectMessageCount() == 0);
 
-    message = netif.GetInstance().mMessagePool.New(Message::kTypeSupervision, sizeof(uint8_t));
+    message = netif.GetInstance().GetMessagePool().New(Message::kTypeSupervision, sizeof(uint8_t));
     VerifyOrExit(message != NULL);
 
     // Supervision message is an empty payload 15.4 data frame.
@@ -170,7 +170,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     ChildSupervisor &supervisor = *static_cast<ChildSupervisor *>(aContext.GetContext());
 #else
-    ChildSupervisor &supervisor = otGetThreadNetif().GetChildSupervisor();
+    ChildSupervisor &supervisor = Instance::Get().GetThreadNetif().GetChildSupervisor();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return supervisor;
@@ -178,7 +178,7 @@
 
 #endif // #if OPENTHREAD_FTD
 
-SupervisionListener::SupervisionListener(otInstance &aInstance) :
+SupervisionListener::SupervisionListener(Instance &aInstance) :
     InstanceLocator(aInstance),
     mTimeout(0),
     mTimer(aInstance, &SupervisionListener::HandleTimer, this)
@@ -262,7 +262,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     SupervisionListener &listener = *static_cast<SupervisionListener *>(aContext.GetContext());
 #else
-    SupervisionListener &listener = otGetThreadNetif().GetSupervisionListener();
+    SupervisionListener &listener = Instance::Get().GetThreadNetif().GetSupervisionListener();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return listener;
diff --git a/src/core/utils/child_supervision.hpp b/src/core/utils/child_supervision.hpp
index c6d45cc..fd2f99a 100644
--- a/src/core/utils/child_supervision.hpp
+++ b/src/core/utils/child_supervision.hpp
@@ -95,7 +95,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    explicit ChildSupervisor(otInstance &aInstance);
+    explicit ChildSupervisor(Instance &aInstance);
 
     /**
      * This method starts the child supervision process on parent.
@@ -194,7 +194,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    explicit SupervisionListener(otInstance &aInstance);
+    explicit SupervisionListener(Instance &aInstance);
 
     /**
      * This method starts the supervision listener operation.
diff --git a/src/core/utils/jam_detector.cpp b/src/core/utils/jam_detector.cpp
index 183b0a3..23ae0d7 100644
--- a/src/core/utils/jam_detector.cpp
+++ b/src/core/utils/jam_detector.cpp
@@ -36,8 +36,8 @@
 #include <openthread/openthread.h>
 #include <openthread/platform/random.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "thread/thread_netif.hpp"
 
 #if OPENTHREAD_ENABLE_JAM_DETECTION
@@ -45,7 +45,7 @@
 namespace ot {
 namespace Utils {
 
-JamDetector::JamDetector(otInstance &aInstance) :
+JamDetector::JamDetector(Instance &aInstance) :
     InstanceLocator(aInstance),
     mHandler(NULL),
     mContext(NULL),
@@ -243,7 +243,7 @@
 #if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
     JamDetector &detector = *static_cast<JamDetector *>(aContext.GetContext());
 #else
-    JamDetector &detector = otGetThreadNetif().GetJamDetector();
+    JamDetector &detector = Instance::Get().GetThreadNetif().GetJamDetector();
     OT_UNUSED_VARIABLE(aContext);
 #endif
     return detector;
diff --git a/src/core/utils/jam_detector.hpp b/src/core/utils/jam_detector.hpp
index ae8dac2..33c857a 100644
--- a/src/core/utils/jam_detector.hpp
+++ b/src/core/utils/jam_detector.hpp
@@ -65,7 +65,7 @@
      * @param[in]  aInstance     A reference to the OpenThread instance.
      *
      */
-    explicit JamDetector(otInstance &aInstance);
+    explicit JamDetector(Instance &aInstance);
 
     /**
      * Start the jamming detection.
diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp
index 29f37d8..9d6cb58 100644
--- a/src/ncp/ncp_base.cpp
+++ b/src/ncp/ncp_base.cpp
@@ -44,9 +44,9 @@
 #include <openthread/platform/misc.h>
 #include <openthread/platform/radio.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "mac/mac_frame.hpp"
 #include "net/ip6.hpp"
 
@@ -498,7 +498,7 @@
 
 NcpBase *NcpBase::sNcpInstance = NULL;
 
-NcpBase::NcpBase(otInstance *aInstance):
+NcpBase::NcpBase(Instance *aInstance):
     mInstance(aInstance),
     mTxFrameBuffer(mTxBuffer, sizeof(mTxBuffer)),
     mEncoder(mTxFrameBuffer),
diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp
index af785a9..cc5a0ef 100644
--- a/src/ncp/ncp_base.hpp
+++ b/src/ncp/ncp_base.hpp
@@ -48,6 +48,7 @@
 #include <openthread/types.h>
 
 #include "changed_props_set.hpp"
+#include "common/instance.hpp"
 #include "common/tasklet.hpp"
 #include "ncp/ncp_buffer.hpp"
 #include "ncp/spinel_decoder.hpp"
@@ -73,7 +74,7 @@
      * @param[in]  aInstance  The OpenThread instance structure.
      *
      */
-    NcpBase(otInstance *aInstance);
+    NcpBase(Instance *aInstance);
 
     /**
      * This static method returns the pointer to the single NCP instance.
@@ -622,7 +623,7 @@
     static NcpBase *sNcpInstance;
     static spinel_status_t ThreadErrorToSpinelStatus(otError aError);
     static uint8_t LinkFlagsToFlagByte(bool aRxOnWhenIdle, bool aSecureDataRequests, bool aDeviceType, bool aNetworkData);
-    otInstance *mInstance;
+    Instance *mInstance;
     NcpFrameBuffer  mTxFrameBuffer;
     SpinelEncoder mEncoder;
     SpinelDecoder mDecoder;
diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp
index 2ea1d5f..8f91164 100644
--- a/src/ncp/ncp_base_ftd.cpp
+++ b/src/ncp/ncp_base_ftd.cpp
@@ -43,9 +43,9 @@
 #include <openthread/tmf_proxy.h>
 #endif
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #if OPENTHREAD_ENABLE_COMMISSIONER
 #include "meshcop/commissioner.hpp"
 #endif
diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp
index 590ff44..5823218 100644
--- a/src/ncp/ncp_base_mtd.cpp
+++ b/src/ncp/ncp_base_mtd.cpp
@@ -48,9 +48,9 @@
 #include <openthread/thread_ftd.h>
 #endif
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "net/ip6.hpp"
 
 #if OPENTHREAD_MTD || OPENTHREAD_FTD
diff --git a/src/ncp/ncp_base_radio.cpp b/src/ncp/ncp_base_radio.cpp
index 6c5f67e..31f393d 100644
--- a/src/ncp/ncp_base_radio.cpp
+++ b/src/ncp/ncp_base_radio.cpp
@@ -43,9 +43,9 @@
 #include <openthread/platform/misc.h>
 #include <openthread/platform/radio.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "net/ip6.hpp"
 
 #if OPENTHREAD_ENABLE_RAW_LINK_API
diff --git a/src/ncp/ncp_spi.cpp b/src/ncp/ncp_spi.cpp
index 06466df..c3e46fe 100644
--- a/src/ncp/ncp_spi.cpp
+++ b/src/ncp/ncp_spi.cpp
@@ -37,9 +37,9 @@
 #include <openthread/platform/misc.h>
 
 #include "openthread-core-config.h"
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/new.hpp"
 #include "net/ip6.hpp"
 
@@ -58,8 +58,9 @@
 extern "C" void otNcpInit(otInstance *aInstance)
 {
     NcpSpi *ncpSpi = NULL;
+    Instance *instance = static_cast<Instance *>(aInstance);
 
-    ncpSpi = new(&sNcpRaw) NcpSpi(aInstance);
+    ncpSpi = new(&sNcpRaw) NcpSpi(instance);
 
     if (ncpSpi == NULL || ncpSpi != NcpBase::GetNcpInstance())
     {
@@ -99,7 +100,7 @@
     return ( header[3] + static_cast<uint16_t>(header[4] << 8) );
 }
 
-NcpSpi::NcpSpi(otInstance *aInstance) :
+NcpSpi::NcpSpi(Instance *aInstance) :
     NcpBase(aInstance),
     mTxState(kTxStateIdle),
     mHandlingRxFrame(false),
diff --git a/src/ncp/ncp_spi.hpp b/src/ncp/ncp_spi.hpp
index c0e20ab..588e9ce 100644
--- a/src/ncp/ncp_spi.hpp
+++ b/src/ncp/ncp_spi.hpp
@@ -49,7 +49,7 @@
      * @param[in]  aInstance  A pointer to the OpenThread instance structure.
      *
      */
-    NcpSpi(otInstance *aInstance);
+    NcpSpi(Instance *aInstance);
 
 private:
     enum
diff --git a/src/ncp/ncp_uart.cpp b/src/ncp/ncp_uart.cpp
index 2ad094a..cc78797 100644
--- a/src/ncp/ncp_uart.cpp
+++ b/src/ncp/ncp_uart.cpp
@@ -40,10 +40,10 @@
 #include <openthread/platform/misc.h>
 
 #include "openthread-core-config.h"
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
 #include "common/new.hpp"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "net/ip6.hpp"
 
 #if OPENTHREAD_ENABLE_NCP_UART
@@ -56,7 +56,9 @@
 extern "C" void otNcpInit(otInstance *aInstance)
 {
     NcpUart *ncpUart = NULL;
-    ncpUart = new(&sNcpRaw) NcpUart(aInstance);
+    Instance *instance = static_cast<Instance *>(aInstance);
+
+    ncpUart = new(&sNcpRaw) NcpUart(instance);
 
     if (ncpUart == NULL || ncpUart != NcpBase::GetNcpInstance())
     {
@@ -91,7 +93,7 @@
     return mBuffer;
 }
 
-NcpUart::NcpUart(otInstance *aInstance):
+NcpUart::NcpUart(Instance *aInstance):
     NcpBase(aInstance),
     mFrameDecoder(mRxBuffer, sizeof(mRxBuffer), &NcpUart::HandleFrame, &NcpUart::HandleError, this),
     mUartBuffer(),
diff --git a/src/ncp/ncp_uart.hpp b/src/ncp/ncp_uart.hpp
index 37ba27c..f13f618 100644
--- a/src/ncp/ncp_uart.hpp
+++ b/src/ncp/ncp_uart.hpp
@@ -52,7 +52,7 @@
      * @param[in]  aInstance  The OpenThread instance structure.
      *
      */
-    NcpUart(otInstance *aInstance);
+    NcpUart(Instance *aInstance);
 
     /**
      * This method is called when uart tx is finished. It prepares and sends the next data chunk (if any) to uart.
diff --git a/tests/unit/test_lowpan.cpp b/tests/unit/test_lowpan.cpp
index e93ecc3..267412f 100644
--- a/tests/unit/test_lowpan.cpp
+++ b/tests/unit/test_lowpan.cpp
@@ -36,7 +36,7 @@
 
 namespace ot {
 
-otInstance *sInstance;
+ot::Instance *sInstance;
 Ip6::Ip6 *sIp6;
 ThreadNetif *sThreadNetif;
 Lowpan::Lowpan *sLowpan;
@@ -176,7 +176,7 @@
 
     if (aCompress)
     {
-        VerifyOrQuit((message = sInstance->mMessagePool.New(Message::kTypeIp6, 0)) != NULL,
+        VerifyOrQuit((message = sInstance->GetMessagePool().New(Message::kTypeIp6, 0)) != NULL,
                      "6lo: Ip6::NewMessage failed");
 
         aVector.GetUncompressedStream(*message);
@@ -211,7 +211,7 @@
 
     if (aDecompress)
     {
-        VerifyOrQuit((message = sInstance->mMessagePool.New(Message::kTypeIp6, 0)) != NULL,
+        VerifyOrQuit((message = sInstance->GetMessagePool().New(Message::kTypeIp6, 0)) != NULL,
                      "6lo: Ip6::NewMessage failed");
 
         int decompressedBytes = sLowpan->Decompress(*message, aVector.mMacSource, aVector.mMacDestination,
@@ -1866,8 +1866,8 @@
 
     VerifyOrQuit(sInstance != NULL, "NULL instance");
 
-    sIp6 = &sInstance->mIp6;
-    sThreadNetif = &sInstance->mThreadNetif;
+    sIp6 = &sInstance->GetIp6();
+    sThreadNetif = &sInstance->GetThreadNetif();
     sLowpan = &sThreadNetif->GetLowpan();
 
     Init();
diff --git a/tests/unit/test_lowpan.hpp b/tests/unit/test_lowpan.hpp
index 63ceb5e..6d265cf 100644
--- a/tests/unit/test_lowpan.hpp
+++ b/tests/unit/test_lowpan.hpp
@@ -32,7 +32,7 @@
 
 #include <openthread/openthread.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 #include "mac/mac.hpp"
 #include "net/ip6_headers.hpp"
 #include "thread/lowpan.hpp"
diff --git a/tests/unit/test_message.cpp b/tests/unit/test_message.cpp
index 8a5312f..af656bd 100644
--- a/tests/unit/test_message.cpp
+++ b/tests/unit/test_message.cpp
@@ -28,8 +28,8 @@
 
 #include <openthread/openthread.h>
 
-#include "openthread-instance.h"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/message.hpp"
 #include "utils/wrap_string.h"
 
@@ -38,16 +38,16 @@
 
 void TestMessage(void)
 {
-    otInstance *instance;
+    ot::Instance *instance;
     ot::MessagePool *messagePool;
     ot::Message *message;
     uint8_t writeBuffer[1024];
     uint8_t readBuffer[1024];
 
-    instance = testInitInstance();
+    instance = static_cast<ot::Instance *>(testInitInstance());
     VerifyOrQuit(instance != NULL, "Null OpenThread instance\n");
 
-    messagePool = &instance->mMessagePool;
+    messagePool = &instance->GetMessagePool();
 
     for (unsigned i = 0; i < sizeof(writeBuffer); i++)
     {
diff --git a/tests/unit/test_message_queue.cpp b/tests/unit/test_message_queue.cpp
index 7aa06de..fd7c0e3 100644
--- a/tests/unit/test_message_queue.cpp
+++ b/tests/unit/test_message_queue.cpp
@@ -33,8 +33,8 @@
 #include <openthread/config.h>
 #include <openthread/openthread.h>
 
-#include "openthread-instance.h"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/message.hpp"
 #include "utils/wrap_string.h"
 
@@ -42,7 +42,7 @@
 
 #define kNumTestMessages      5
 
-static otInstance *sInstance;
+static ot::Instance *sInstance;
 static ot::MessagePool *sMessagePool;
 
 // This function verifies the content of the message queue to match the passed in messages
@@ -87,7 +87,7 @@
     sInstance = testInitInstance();
     VerifyOrQuit(sInstance != NULL, "Null instance");
 
-    sMessagePool = &sInstance->mMessagePool;
+    sMessagePool = &sInstance->GetMessagePool();
 
     for (int i = 0; i < kNumTestMessages; i++)
     {
diff --git a/tests/unit/test_ncp_buffer.cpp b/tests/unit/test_ncp_buffer.cpp
index b3ab4eb..9b2163a 100644
--- a/tests/unit/test_ncp_buffer.cpp
+++ b/tests/unit/test_ncp_buffer.cpp
@@ -30,8 +30,8 @@
 
 #include <openthread/openthread.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "common/message.hpp"
 #include "ncp/ncp_buffer.hpp"
 
@@ -58,7 +58,7 @@
 static const uint8_t sMysteryText[]    = "4871(\\):|(3$}{4|/4/2%14(\\)";
 static const uint8_t sHexText[]        = "0123456789abcdef";
 
-static otInstance *sInstance;
+static ot::Instance *sInstance;
 static MessagePool *sMessagePool;
 
 struct CallbackContext
@@ -378,7 +378,7 @@
     NcpFrameBuffer::WritePosition pos1, pos2;
 
     sInstance = testInitInstance();
-    sMessagePool = &sInstance->mMessagePool;
+    sMessagePool = &sInstance->GetMessagePool();
 
     for (i = 0; i < sizeof(buffer); i++)
     {
@@ -1005,7 +1005,7 @@
     uint32_t lensArrayCount[kNumPrios];
 
     sInstance = testInitInstance();
-    sMessagePool = &sInstance->mMessagePool;
+    sMessagePool = &sInstance->GetMessagePool();
 
     memset(buffer, 0, sizeof(buffer));
 
diff --git a/tests/unit/test_network_data.cpp b/tests/unit/test_network_data.cpp
index 8b34740..6356165 100644
--- a/tests/unit/test_network_data.cpp
+++ b/tests/unit/test_network_data.cpp
@@ -28,7 +28,7 @@
 
 #include <openthread/config.h>
 
-#include "openthread-instance.h"
+#include "common/instance.hpp"
 #include "thread/network_data_local.hpp"
 
 #include "test_platform.h"
@@ -39,7 +39,7 @@
 class TestNetworkData: public NetworkData::NetworkData
 {
 public:
-    TestNetworkData(otInstance *aInstance, const uint8_t *aTlvs, uint8_t aTlvsLength):
+    TestNetworkData(ot::Instance *aInstance, const uint8_t *aTlvs, uint8_t aTlvsLength):
         NetworkData::NetworkData(*aInstance, false) {
         memcpy(mTlvs, aTlvs, aTlvsLength);
         mLength = aTlvsLength;
@@ -72,7 +72,7 @@
 
 void TestNetworkDataIterator(void)
 {
-    otInstance *instance;
+    ot::Instance *instance;
     otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT;
     otExternalRouteConfig config;
 
diff --git a/tests/unit/test_platform.cpp b/tests/unit/test_platform.cpp
index 972084e..a5cb469 100644
--- a/tests/unit/test_platform.cpp
+++ b/tests/unit/test_platform.cpp
@@ -77,7 +77,7 @@
     g_testPlatRadioGetTransmitBuffer = NULL;
 }
 
-otInstance *testInitInstance(void)
+ot::Instance *testInitInstance(void)
 {
     otInstance *instance = NULL;
 
@@ -99,7 +99,7 @@
     instance = otInstanceInitSingle();
 #endif
 
-    return instance;
+    return static_cast<ot::Instance *>(instance);
 }
 
 void testFreeInstance(otInstance *aInstance)
diff --git a/tests/unit/test_platform.h b/tests/unit/test_platform.h
index 992fe90..87b3e7c 100644
--- a/tests/unit/test_platform.h
+++ b/tests/unit/test_platform.h
@@ -46,6 +46,7 @@
 #include <openthread/platform/random.h>
 
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 
 #include "test_util.h"
 
@@ -89,7 +90,7 @@
 extern testPlatRadioTransmit            g_testPlatRadioTransmit;
 extern testPlatRadioGetTransmitBuffer   g_testPlatRadioGetTransmitBuffer;
 
-otInstance *testInitInstance(void);
+ot::Instance *testInitInstance(void);
 void testFreeInstance(otInstance *aInstance);
 
 // Resets platform functions to defaults
diff --git a/tests/unit/test_priority_queue.cpp b/tests/unit/test_priority_queue.cpp
index 5929d4c..2338b9c 100644
--- a/tests/unit/test_priority_queue.cpp
+++ b/tests/unit/test_priority_queue.cpp
@@ -29,9 +29,9 @@
 #include <stdarg.h>
 
 #include <openthread/openthread.h>
-#include <openthread-instance.h>
 
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/message.hpp"
 #include "utils/wrap_string.h"
 
@@ -208,7 +208,7 @@
 
 void TestPriorityQueue(void)
 {
-    otInstance *instance;
+    ot::Instance *instance;
     ot::MessagePool *messagePool;
     ot::PriorityQueue queue;
     ot::MessageQueue messageQueue;
@@ -221,7 +221,7 @@
     instance = testInitInstance();
     VerifyOrQuit(instance != NULL, "Null OpenThread instance\n");
 
-    messagePool = &instance->mMessagePool;
+    messagePool = &instance->GetMessagePool();
 
     // Allocate messages with different priorities.
     for (int i = 0; i < kNumTestMessages; i++)
diff --git a/tests/unit/test_spinel_decoder.cpp b/tests/unit/test_spinel_decoder.cpp
index 945d106..2a6f666 100644
--- a/tests/unit/test_spinel_decoder.cpp
+++ b/tests/unit/test_spinel_decoder.cpp
@@ -30,8 +30,8 @@
 
 #include <openthread/openthread.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "ncp/spinel_decoder.hpp"
 
 #include "test_util.h"
diff --git a/tests/unit/test_spinel_encoder.cpp b/tests/unit/test_spinel_encoder.cpp
index 1c4017c..1bd5088 100644
--- a/tests/unit/test_spinel_encoder.cpp
+++ b/tests/unit/test_spinel_encoder.cpp
@@ -30,8 +30,8 @@
 
 #include <openthread/openthread.h>
 
-#include "openthread-instance.h"
 #include "common/code_utils.hpp"
+#include "common/instance.hpp"
 #include "ncp/spinel_encoder.hpp"
 
 #include "test_util.h"
diff --git a/tests/unit/test_timer.cpp b/tests/unit/test_timer.cpp
index 2ba2408..70b027d 100644
--- a/tests/unit/test_timer.cpp
+++ b/tests/unit/test_timer.cpp
@@ -28,8 +28,8 @@
 
 #include "test_platform.h"
 
-#include "openthread-instance.h"
 #include "common/debug.hpp"
+#include "common/instance.hpp"
 #include "common/timer.hpp"
 
 enum
@@ -85,7 +85,7 @@
 class TestTimer: public ot::TimerMilli
 {
 public:
-    TestTimer(otInstance &aInstance):
+    TestTimer(ot::Instance &aInstance):
         ot::TimerMilli(aInstance, TestTimer::HandleTimerFired, NULL),
         mFiredCounter(0)
     { }
@@ -114,7 +114,7 @@
 {
     const uint32_t kTimeT0 = 1000;
     const uint32_t kTimerInterval = 10;
-    otInstance *instance = testInitInstance();
+    ot::Instance *instance = testInitInstance();
     TestTimer timer(*instance);
 
     // Test one Timer basic operation.
@@ -240,7 +240,7 @@
 {
     const uint32_t kTimeT0 = 1000;
     const uint32_t kTimerInterval = 10;
-    otInstance *instance = testInitInstance();
+    ot::Instance *instance = testInitInstance();
     TestTimer timer1(*instance);
     TestTimer timer2(*instance);
 
@@ -524,7 +524,7 @@
         11
     };
 
-    otInstance *instance = testInitInstance();
+    ot::Instance *instance = testInitInstance();
 
     TestTimer timer0(*instance);
     TestTimer timer1(*instance);