diff --git a/doc/17-language-reference.md b/doc/17-language-reference.md
index 0e48a6c25..4de8afbfd 100644
--- a/doc/17-language-reference.md
+++ b/doc/17-language-reference.md
@@ -232,6 +232,7 @@ The `using` keyword only has an effect for the current file and only for code th
 The following namespaces are automatically imported as if by using the `using` keyword:
 
 * System
+* System.Configuration
 * Types
 * Icinga
 
diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp
index 5e8cbd8ec..a2bf8001c 100644
--- a/icinga-app/icinga.cpp
+++ b/icinga-app/icinga.cpp
@@ -23,6 +23,7 @@
 #include "config/configitembuilder.hpp"
 #include "config/expression.hpp"
 #include "base/application.hpp"
+#include "base/configuration.hpp"
 #include "base/logger.hpp"
 #include "base/timer.hpp"
 #include "base/utility.hpp"
@@ -101,7 +102,7 @@ static void HandleLegacyDefines()
 	String dataPrefix = Utility::GetIcingaDataPath();
 #endif /* _WIN32 */
 
-	Value localStateDir = Application::GetConst("LocalStateDir");
+	Value localStateDir = Configuration::LocalStateDir;
 
 	if (!localStateDir.IsEmpty()) {
 		Log(LogWarning, "icinga-app")
@@ -110,51 +111,51 @@ static void HandleLegacyDefines()
 			<< " For compatibility reasons, these are now set based on the 'LocalStateDir' constant.";
 
 #ifdef _WIN32
-		ScriptGlobal::Set("DataDir", localStateDir + "\\lib\\icinga2");
-		ScriptGlobal::Set("LogDir", localStateDir + "\\log\\icinga2");
-		ScriptGlobal::Set("CacheDir", localStateDir + "\\cache\\icinga2");
-		ScriptGlobal::Set("SpoolDir", localStateDir + "\\spool\\icinga2");
+		Configuration::DataDir = localStateDir + "\\lib\\icinga2";
+		Configuration::LogDir = localStateDir + "\\log\\icinga2";
+		Configuration::CacheDir = localStateDir + "\\cache\\icinga2";
+		Configuration::SpoolDir = localStateDir + "\\spool\\icinga2";
 	} else {
-		ScriptGlobal::Set("LocalStateDir", dataPrefix + "\\var");
+		Configuration::LocalStateDir = dataPrefix + "\\var";
 #else /* _WIN32 */
-		ScriptGlobal::Set("DataDir", localStateDir + "/lib/icinga2");
-		ScriptGlobal::Set("LogDir", localStateDir + "/log/icinga2");
-		ScriptGlobal::Set("CacheDir", localStateDir + "/cache/icinga2");
-		ScriptGlobal::Set("SpoolDir", localStateDir + "/spool/icinga2");
+		Configuration::DataDir = localStateDir + "/lib/icinga2";
+		Configuration::LogDir = localStateDir + "/log/icinga2";
+		Configuration::CacheDir = localStateDir + "/cache/icinga2";
+		Configuration::SpoolDir = localStateDir + "/spool/icinga2";
 	} else {
-		ScriptGlobal::Set("LocalStateDir", ICINGA_LOCALSTATEDIR);
+		Configuration::LocalStateDir = ICINGA_LOCALSTATEDIR;
 #endif /* _WIN32 */
 	}
 
-	Value sysconfDir = Application::GetConst("SysconfDir");
+	Value sysconfDir = Configuration::SysconfDir;
 	if (!sysconfDir.IsEmpty()) {
 		Log(LogWarning, "icinga-app")
 			<< "Please do not set the deprecated 'Sysconfdir' constant, use the 'ConfigDir' constant instead! For compatibility reasons, their value is set based on the 'SysconfDir' constant.";
 
 #ifdef _WIN32
-		ScriptGlobal::Set("ConfigDir", sysconfDir + "\\icinga2");
+		Configuration::ConfigDir = sysconfDir + "\\icinga2";
 	} else {
-		ScriptGlobal::Set("SysconfDir", dataPrefix + "\\etc");
+		Configuration::SysconfDir = dataPrefix + "\\etc";
 #else /* _WIN32 */
-		ScriptGlobal::Set("ConfigDir", sysconfDir + "/icinga2");
+		Configuration::ConfigDir = sysconfDir + "/icinga2";
 	} else {
-		ScriptGlobal::Set("SysconfDir", ICINGA_SYSCONFDIR);
+		Configuration::SysconfDir = ICINGA_SYSCONFDIR;
 #endif /* _WIN32 */
 	}
 
-	Value runDir = Application::GetConst("RunDir");
+	Value runDir = Configuration::RunDir;
 	if (!runDir.IsEmpty()) {
 		Log(LogWarning, "icinga-app")
 			<< "Please do not set the deprecated 'RunDir' constant, use the 'InitRunDir' constant instead! For compatiblity reasons, their value is set based on the 'RunDir' constant.";
 
 #ifdef _WIN32
-		ScriptGlobal::Set("InitRunDir", runDir + "\\icinga2");
+		Configuration::InitRunDir = runDir + "\\icinga2";
 	} else {
-		ScriptGlobal::Set("RunDir", dataPrefix + "\\var\\run");
+		Configuration::RunDir = dataPrefix + "\\var\\run";
 #else /* _WIN32 */
-		ScriptGlobal::Set("InitRunDir", runDir + "/icinga2");
+		Configuration::InitRunDir = runDir + "/icinga2";
 	} else {
-		ScriptGlobal::Set("RunDir", ICINGA_RUNDIR);
+		Configuration::RunDir = ICINGA_RUNDIR;
 #endif /* _WIN32 */
 	}
 }
@@ -199,43 +200,43 @@ static int Main()
 	String dataPrefix = Utility::GetIcingaDataPath();
 
 	if (!binaryPrefix.IsEmpty() && !dataPrefix.IsEmpty()) {
-		Application::DeclareConst("PrefixDir", binaryPrefix);
-		Application::DeclareConst("ProgramData", dataPrefix);
+		Configuration::PrefixDir = binaryPrefix;
+		Configuration::ProgramData = dataPrefix;
 
-		Application::DeclareConst("ConfigDir", dataPrefix + "\\etc\\icinga2");
+		Configuration::ConfigDir = dataPrefix + "\\etc\\icinga2";
 
-		Application::DeclareConst("DataDir", dataPrefix + "\\var\\lib\\icinga2");
-		Application::DeclareConst("LogDir", dataPrefix + "\\var\\log\\icinga2");
-		Application::DeclareConst("CacheDir", dataPrefix + "\\var\\cache\\icinga2");
-		Application::DeclareConst("SpoolDir", dataPrefix + "\\var\\spool\\icinga2");
+		Configuration::DataDir =  dataPrefix + "\\var\\lib\\icinga2";
+		Configuration::LogDir = dataPrefix + "\\var\\log\\icinga2";
+		Configuration::CacheDir = dataPrefix + "\\var\\cache\\icinga2";
+		Configuration::SpoolDir = dataPrefix + "\\var\\spool\\icinga2";
 
 		/* Internal constants. */
-		Application::DeclareConst("PkgDataDir", binaryPrefix + "\\share\\icinga2");
-		Application::DeclareConst("IncludeConfDir", binaryPrefix + "\\share\\icinga2\\include");
+		Configuration::PkgDataDir = binaryPrefix + "\\share\\icinga2";
+		Configuration::IncludeConfDir = binaryPrefix + "\\share\\icinga2\\include";
 	} else {
 		Log(LogWarning, "icinga-app", "Registry key could not be read. Falling back to built-in paths.");
 
 #endif /* _WIN32 */
-		Application::DeclareConst("ConfigDir", ICINGA_CONFIGDIR);
+		Configuration::ConfigDir = ICINGA_CONFIGDIR;
 
-		Application::DeclareConst("DataDir", ICINGA_DATADIR);
-		Application::DeclareConst("LogDir", ICINGA_LOGDIR);
-		Application::DeclareConst("CacheDir", ICINGA_CACHEDIR);
-		Application::DeclareConst("SpoolDir", ICINGA_SPOOLDIR);
+		Configuration::DataDir = ICINGA_DATADIR;
+		Configuration::LogDir = ICINGA_LOGDIR;
+		Configuration::CacheDir = ICINGA_CACHEDIR;
+		Configuration::SpoolDir = ICINGA_SPOOLDIR;
 
-		Application::DeclareConst("PrefixDir", ICINGA_PREFIX);
+		Configuration::PrefixDir = ICINGA_PREFIX;
 
 		/* Internal constants. */
-		Application::DeclareConst("PkgDataDir", ICINGA_PKGDATADIR);
-		Application::DeclareConst("IncludeConfDir", ICINGA_INCLUDECONFDIR);
+		Configuration::PkgDataDir = ICINGA_PKGDATADIR;
+		Configuration::IncludeConfDir = ICINGA_INCLUDECONFDIR;
 
-		Application::DeclareConst("InitRunDir", ICINGA_INITRUNDIR);
+		Configuration::InitRunDir = ICINGA_INITRUNDIR;
 
 #ifdef _WIN32
 	}
 #endif /* _WIN32 */
 
-	Application::DeclareConst("ZonesDir", Application::GetConst("ConfigDir") + "/zones.d");
+	Configuration::ZonesDir = Configuration::ConfigDir + "/zones.d";
 
 	String icingaUser = Utility::GetFromEnvironment("ICINGA2_USER");
 	if (icingaUser.IsEmpty())
@@ -245,17 +246,17 @@ static int Main()
 	if (icingaGroup.IsEmpty())
 		icingaGroup = ICINGA_GROUP;
 
-	Application::DeclareConst("RunAsUser", icingaUser);
-	Application::DeclareConst("RunAsGroup", icingaGroup);
+	Configuration::RunAsUser = icingaUser;
+	Configuration::RunAsGroup = icingaGroup;
 
 	if (!autocomplete) {
 #ifdef RLIMIT_NOFILE
 		String rLimitFiles = Utility::GetFromEnvironment("ICINGA2_RLIMIT_FILES");
 		if (rLimitFiles.IsEmpty())
-			Application::DeclareConst("RLimitFiles", Application::GetDefaultRLimitFiles());
+			Configuration::RLimitFiles = Application::GetDefaultRLimitFiles();
 		else {
 			try {
-				Application::DeclareConst("RLimitFiles", Convert::ToLong(rLimitFiles));
+				Configuration::RLimitFiles = Convert::ToLong(rLimitFiles);
 			} catch (const std::invalid_argument& ex) {
 				std::cout
 					<< "Error setting \"ICINGA2_RLIMIT_FILES\": " << ex.what() << '\n';
@@ -267,10 +268,10 @@ static int Main()
 #ifdef RLIMIT_NPROC
 		String rLimitProcesses = Utility::GetFromEnvironment("ICINGA2_RLIMIT_PROCESSES");
 		if (rLimitProcesses.IsEmpty())
-			Application::DeclareConst("RLimitProcesses", Application::GetDefaultRLimitProcesses());
+			Configuration::RLimitProcesses = Application::GetDefaultRLimitProcesses();
 		else {
 			try {
-				Application::DeclareConst("RLimitProcesses", Convert::ToLong(rLimitProcesses));
+				Configuration::RLimitProcesses = Convert::ToLong(rLimitProcesses);
 			} catch (const std::invalid_argument& ex) {
 				std::cout
 					<< "Error setting \"ICINGA2_RLIMIT_PROCESSES\": " << ex.what() << '\n';
@@ -282,10 +283,10 @@ static int Main()
 #ifdef RLIMIT_STACK
 		String rLimitStack = Utility::GetFromEnvironment("ICINGA2_RLIMIT_STACK");
 		if (rLimitStack.IsEmpty())
-			Application::DeclareConst("RLimitStack", Application::GetDefaultRLimitStack());
+			Configuration::RLimitStack = Application::GetDefaultRLimitStack();
 		else {
 			try {
-				Application::DeclareConst("RLimitStack", Convert::ToLong(rLimitStack));
+				Configuration::RLimitStack = Convert::ToLong(rLimitStack);
 			} catch (const std::invalid_argument& ex) {
 				std::cout
 					<< "Error setting \"ICINGA2_RLIMIT_STACK\": " << ex.what() << '\n';
@@ -295,10 +296,9 @@ static int Main()
 #endif /* RLIMIT_STACK */
 	}
 
-	Application::DeclareConst("Concurrency", std::thread::hardware_concurrency());
-	Application::DeclareConst("MaxConcurrentChecks", Application::GetDefaultMaxConcurrentChecks());
+	ScriptGlobal::Set("MaxConcurrentChecks", Application::GetDefaultMaxConcurrentChecks());
 
-	ScriptGlobal::Set("AttachDebugger", false);
+	ScriptGlobal::Set("Environment", "production");
 
 	ScriptGlobal::Set("System.PlatformKernel", Utility::GetPlatformKernel(), true);
 	ScriptGlobal::Set("System.PlatformKernelVersion", Utility::GetPlatformKernelVersion(), true);
@@ -360,7 +360,7 @@ static int Main()
 	std::ifstream userFile;
 
 	/* The implicit string assignment is needed for Windows builds. */
-	String configDir = Application::GetConst("ConfigDir");
+	String configDir = Configuration::ConfigDir;
 	userFile.open(configDir + "/user");
 
 	if (userFile && command && !Application::IsProcessElevated()) {
@@ -462,19 +462,21 @@ static int Main()
 		}
 	}
 
+	Configuration::SetReadOnly(true);
+
 	/* Ensure that all defined constants work in the way we expect them. */
 	HandleLegacyDefines();
 
 	if (vm.count("script-debugger"))
 		Application::SetScriptDebuggerEnabled(true);
 
-	Application::DeclareConst("StatePath", Application::GetConst("DataDir") + "/icinga2.state");
-	Application::DeclareConst("ModAttrPath", Application::GetConst("DataDir") + "/modified-attributes.conf");
-	Application::DeclareConst("ObjectsPath", Application::GetConst("CacheDir") + "/icinga2.debug");
-	Application::DeclareConst("VarsPath", Application::GetConst("CacheDir") + "/icinga2.vars");
-	Application::DeclareConst("PidPath", Application::GetConst("InitRunDir") + "/icinga2.pid");
+	Configuration::StatePath = Configuration::DataDir + "/icinga2.state";
+	Configuration::ModAttrPath = Configuration::DataDir + "/modified-attributes.conf";
+	Configuration::ObjectsPath = Configuration::CacheDir + "/icinga2.debug";
+	Configuration::VarsPath = Configuration::CacheDir + "/icinga2.vars";
+	Configuration::PidPath = Configuration::InitRunDir + "/icinga2.pid";
 
-	ConfigCompiler::AddIncludeSearchDir(Application::GetConst("IncludeConfDir"));
+	ConfigCompiler::AddIncludeSearchDir(Configuration::IncludeConfDir);
 
 	if (!autocomplete && vm.count("include")) {
 		for (const String& includePath : vm["include"].as<std::vector<std::string> >()) {
@@ -584,8 +586,8 @@ static int Main()
 				return 0;
 			}
 		} else if (command && command->GetImpersonationLevel() == ImpersonateIcinga) {
-			String group = Application::GetConst("RunAsGroup");
-			String user = Application::GetConst("RunAsUser");
+			String group = Configuration::RunAsGroup;
+			String user = Configuration::RunAsUser;
 
 			errno = 0;
 			struct group *gr = getgrnam(group.CStr());
diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt
index 3cdc08556..9988d8e70 100644
--- a/lib/base/CMakeLists.txt
+++ b/lib/base/CMakeLists.txt
@@ -17,6 +17,7 @@
 
 mkclass_target(application.ti application-ti.cpp application-ti.hpp)
 mkclass_target(configobject.ti configobject-ti.cpp configobject-ti.hpp)
+mkclass_target(configuration.ti configuration-ti.cpp configuration-ti.hpp)
 mkclass_target(datetime.ti datetime-ti.cpp datetime-ti.hpp)
 mkclass_target(filelogger.ti filelogger-ti.cpp filelogger-ti.hpp)
 mkclass_target(function.ti function-ti.cpp function-ti.hpp)
@@ -33,6 +34,7 @@ set(base_SOURCES
   boolean.cpp boolean.hpp boolean-script.cpp
   configobject.cpp configobject.hpp configobject-ti.hpp configobject-script.cpp
   configtype.cpp configtype.hpp
+  configuration.cpp configuration.hpp configuration-ti.hpp
   configwriter.cpp configwriter.hpp
   console.cpp console.hpp
   context.cpp context.hpp
diff --git a/lib/base/application.cpp b/lib/base/application.cpp
index bc8ec1bd4..5fa49a7ba 100644
--- a/lib/base/application.cpp
+++ b/lib/base/application.cpp
@@ -168,7 +168,7 @@ void Application::SetResourceLimits()
 	rlimit rl;
 
 #	ifdef RLIMIT_NOFILE
-	rlim_t fileLimit = GetConst("RLimitFiles");
+	rlim_t fileLimit = Configuration::RLimitFiles;
 
 	if (fileLimit != 0) {
 		if (fileLimit < GetDefaultRLimitFiles()) {
@@ -189,7 +189,7 @@ void Application::SetResourceLimits()
 	}
 
 #	ifdef RLIMIT_NPROC
-	rlim_t processLimit = GetConst("RLimitProcesses");
+	rlim_t processLimit = Configuration::RLimitProcesses;
 
 	if (processLimit != 0) {
 		if (processLimit < GetDefaultRLimitProcesses()) {
@@ -228,7 +228,7 @@ void Application::SetResourceLimits()
 
 	rlim_t stackLimit;
 
-	stackLimit = GetConst("RLimitStack");
+	stackLimit = Configuration::RLimitStack;
 
 	if (stackLimit != 0) {
 		if (stackLimit < GetDefaultRLimitStack()) {
@@ -549,30 +549,32 @@ void Application::DisplayInfoMessage(std::ostream& os, bool skipVersion)
 		<< "  Kernel version: " << Utility::GetPlatformKernelVersion() << "\n"
 		<< "  Architecture: " << Utility::GetPlatformArchitecture() << "\n";
 
+	Namespace::Ptr systemNS = ScriptGlobal::Get("System");
+
 	os << "\nBuild information:\n"
-		<< "  Compiler: " << ScriptGlobal::Get("BuildCompilerName") << " " << ScriptGlobal::Get("BuildCompilerVersion") << "\n"
-		<< "  Build host: " << ScriptGlobal::Get("BuildHostName") << "\n";
+		<< "  Compiler: " << systemNS->Get("BuildCompilerName") << " " << systemNS->Get("BuildCompilerVersion") << "\n"
+		<< "  Build host: " << systemNS->Get("BuildHostName") << "\n";
 
 	os << "\nApplication information:\n"
 		<< "\nGeneral paths:\n"
-		<< "  Config directory: " << GetConst("ConfigDir") << "\n"
-		<< "  Data directory: " << GetConst("DataDir") << "\n"
-		<< "  Log directory: " << GetConst("LogDir") << "\n"
-		<< "  Cache directory: " << GetConst("CacheDir") << "\n"
-		<< "  Spool directory: " << GetConst("SpoolDir") << "\n"
-		<< "  Run directory: " << GetConst("InitRunDir") << "\n"
+		<< "  Config directory: " << Configuration::ConfigDir << "\n"
+		<< "  Data directory: " << Configuration::DataDir << "\n"
+		<< "  Log directory: " << Configuration::LogDir << "\n"
+		<< "  Cache directory: " << Configuration::CacheDir << "\n"
+		<< "  Spool directory: " << Configuration::SpoolDir << "\n"
+		<< "  Run directory: " << Configuration::InitRunDir << "\n"
 		<< "\nOld paths (deprecated):\n"
-		<< "  Installation root: " << GetConst("PrefixDir") << "\n"
-		<< "  Sysconf directory: " << GetConst("SysconfDir") << "\n"
-		<< "  Run directory (base): " << GetConst("RunDir") << "\n"
-		<< "  Local state directory: " << GetConst("LocalStateDir") << "\n"
+		<< "  Installation root: " << Configuration::PrefixDir << "\n"
+		<< "  Sysconf directory: " << Configuration::SysconfDir << "\n"
+		<< "  Run directory (base): " << Configuration::RunDir << "\n"
+		<< "  Local state directory: " << Configuration::LocalStateDir << "\n"
 		<< "\nInternal paths:\n"
-		<< "  Package data directory: " << GetConst("PkgDataDir") << "\n"
-		<< "  State path: " << GetConst("StatePath") << "\n"
-		<< "  Modified attributes path: " << GetConst("ModAttrPath") << "\n"
-		<< "  Objects path: " << GetConst("ObjectsPath") << "\n"
-		<< "  Vars path: " << GetConst("VarsPath") << "\n"
-		<< "  PID path: " << GetConst("PidPath") << "\n";
+		<< "  Package data directory: " << Configuration::PkgDataDir << "\n"
+		<< "  State path: " << Configuration::StatePath << "\n"
+		<< "  Modified attributes path: " << Configuration::ModAttrPath << "\n"
+		<< "  Objects path: " << Configuration::ObjectsPath << "\n"
+		<< "  Vars path: " << Configuration::VarsPath << "\n"
+		<< "  PID path: " << Configuration::PidPath << "\n";
 
 }
 
@@ -590,7 +592,7 @@ void Application::DisplayBugMessage(std::ostream& os)
 
 String Application::GetCrashReportFilename()
 {
-	return GetConst("LogDir") + "/crash/report." + Convert::ToString(Utility::GetTime());
+	return Configuration::LogDir + "/crash/report." + Convert::ToString(Utility::GetTime());
 }
 
 
@@ -740,7 +742,7 @@ void Application::SigUsr2Handler(int)
 	 */
 	Application::Ptr instance = GetInstance();
 	try {
-		instance->UpdatePidFile(GetConst("PidPath"), m_ReloadProcess);
+		instance->UpdatePidFile(Configuration::PidPath, m_ReloadProcess);
 	} catch (const std::exception&) {
 		/* abort restart */
 		Log(LogCritical, "Application", "Cannot update PID file. Aborting restart operation.");
@@ -783,7 +785,7 @@ void Application::SigAbrtHandler(int)
 		}
 	}
 
-	bool interactive_debugger = Convert::ToBool(ScriptGlobal::Get("AttachDebugger"));
+	bool interactive_debugger = Configuration::AttachDebugger;
 
 	if (!interactive_debugger) {
 		std::ofstream ofs;
@@ -893,7 +895,7 @@ void Application::ExceptionHandler()
 		}
 	}
 
-	bool interactive_debugger = Convert::ToBool(ScriptGlobal::Get("AttachDebugger"));
+	bool interactive_debugger = Configuration::AttachDebugger;
 
 	if (!interactive_debugger) {
 		std::ofstream ofs;
@@ -1012,10 +1014,10 @@ int Application::Run()
 #endif /* _WIN32 */
 
 	try {
-		UpdatePidFile(GetConst("PidPath"));
+		UpdatePidFile(Configuration::PidPath);
 	} catch (const std::exception&) {
 		Log(LogCritical, "Application")
-			<< "Cannot update PID file '" << GetConst("PidPath") << "'. Aborting.";
+			<< "Cannot update PID file '" << Configuration::PidPath << "'. Aborting.";
 		return EXIT_FAILURE;
 	}
 
@@ -1097,7 +1099,7 @@ void Application::ClosePidFile(bool unlink)
 
 	if (m_PidFile) {
 		if (unlink) {
-			String pidpath = GetConst("PidPath");
+			String pidpath = Configuration::PidPath;
 			::unlink(pidpath.CStr());
 		}
 
@@ -1165,39 +1167,6 @@ pid_t Application::ReadPidFile(const String& filename)
 	return runningpid;
 }
 
-/**
- * Declares a const with ScriptGlobal
- *
- * @param name The const name.
- * @param value The new value.
- */
-void Application::DeclareConst(const String& name, const Value& value)
-{
-	if (!ScriptGlobal::Exists(name))
-		ScriptGlobal::Set(name, value);
-}
-
-/**
- * Returns the value of a const from ScriptGlobal
- *
- * @param name The const name.
- */
-Value Application::GetConst(const String& name)
-{
-	return GetConst(name, Empty);
-}
-
-/**
- * Returns the value of a const from ScriptGlobal with default value
- *
- * @param name The const name.
- * @param def  The default value.
- */
-Value Application::GetConst(const String& name, Value defaultValue)
-{
-	return ScriptGlobal::Get(name, &defaultValue);
-}
-
 int Application::GetDefaultRLimitFiles()
 {
 	return 16 * 1024;
@@ -1213,17 +1182,6 @@ int Application::GetDefaultRLimitStack()
 	return 256 * 1024;
 }
 
-/**
- * Retrieves the concurrency level.
- *
- * @returns The concurrency level.
- */
-int Application::GetConcurrency()
-{
-	Value defaultConcurrency = std::thread::hardware_concurrency();
-	return ScriptGlobal::Get("Concurrency", &defaultConcurrency);
-}
-
 /**
  * Sets the max concurrent checks.
  *
diff --git a/lib/base/application.hpp b/lib/base/application.hpp
index 88fc51ab6..72a76b6ea 100644
--- a/lib/base/application.hpp
+++ b/lib/base/application.hpp
@@ -23,6 +23,7 @@
 #include "base/i2-base.hpp"
 #include "base/application-ti.hpp"
 #include "base/logger.hpp"
+#include "base/configuration.hpp"
 #include <iosfwd>
 
 namespace icinga
@@ -85,10 +86,6 @@ public:
 
 	static String GetExePath(const String& argv0);
 
-	static void DeclareConst(const String& name, const Value& value);
-	static Value GetConst(const String& name);
-	static Value GetConst(const String& name, Value defaultValue);
-
 #ifdef _WIN32
 	static bool IsProcessElevated();
 #endif /* _WIN32 */
@@ -97,7 +94,6 @@ public:
 	static int GetDefaultRLimitProcesses();
 	static int GetDefaultRLimitStack();
 
-	static int GetConcurrency();
 	static int GetMaxConcurrentChecks();
 	static int GetDefaultMaxConcurrentChecks();
 	static void SetMaxConcurrentChecks(int maxChecks);
diff --git a/lib/base/configobject.cpp b/lib/base/configobject.cpp
index 6aedfaca6..b95a57818 100644
--- a/lib/base/configobject.cpp
+++ b/lib/base/configobject.cpp
@@ -571,7 +571,7 @@ void ConfigObject::RestoreObjects(const String& filename, int attributeTypes)
 
 	unsigned long restored = 0;
 
-	WorkQueue upq(25000, Application::GetConcurrency());
+	WorkQueue upq(25000, Configuration::Concurrency);
 	upq.SetName("ConfigObject::RestoreObjects");
 
 	String message;
diff --git a/lib/base/configuration.cpp b/lib/base/configuration.cpp
new file mode 100644
index 000000000..31f691265
--- /dev/null
+++ b/lib/base/configuration.cpp
@@ -0,0 +1,370 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/)  *
+ *                                                                            *
+ * This program is free software; you can redistribute it and/or              *
+ * modify it under the terms of the GNU General Public License                *
+ * as published by the Free Software Foundation; either version 2             *
+ * of the License, or (at your option) any later version.                     *
+ *                                                                            *
+ * This program is distributed in the hope that it will be useful,            *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
+ * GNU General Public License for more details.                               *
+ *                                                                            *
+ * You should have received a copy of the GNU General Public License          *
+ * along with this program; if not, write to the Free Software Foundation     *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
+ ******************************************************************************/
+
+#include "base/configuration.hpp"
+#include "base/configuration-ti.cpp"
+#include "base/exception.hpp"
+
+using namespace icinga;
+
+REGISTER_TYPE(Configuration);
+
+String Configuration::ApiBindHost;
+String Configuration::ApiBindPort{"5665"};
+bool Configuration::AttachDebugger{false};
+String Configuration::CacheDir;
+int Configuration::Concurrency{static_cast<int>(std::thread::hardware_concurrency())};
+String Configuration::ConfigDir;
+String Configuration::DataDir;
+String Configuration::EventEngine;
+String Configuration::IncludeConfDir;
+String Configuration::InitRunDir;
+String Configuration::LogDir;
+String Configuration::ModAttrPath;
+String Configuration::ObjectsPath;
+String Configuration::PidPath;
+String Configuration::PkgDataDir;
+String Configuration::PrefixDir;
+String Configuration::ProgramData;
+int Configuration::RLimitFiles;
+int Configuration::RLimitProcesses;
+int Configuration::RLimitStack;
+String Configuration::RunAsGroup;
+String Configuration::RunAsUser;
+String Configuration::SpoolDir;
+String Configuration::StatePath;
+String Configuration::VarsPath;
+String Configuration::ZonesDir;
+
+/* deprecated */
+String Configuration::LocalStateDir;
+String Configuration::RunDir;
+String Configuration::SysconfDir;
+
+/* internal */
+bool Configuration::m_ReadOnly{false};
+
+template<typename T>
+void HandleUserWrite(const String& name, T *target, const T& value, bool readOnly)
+{
+	if (readOnly)
+		BOOST_THROW_EXCEPTION(ScriptError("Configuration attribute '" + name + "' is read-only."));
+
+	*target = value;
+}
+
+String Configuration::GetApiBindHost() const
+{
+	return Configuration::ApiBindHost;
+}
+
+void Configuration::SetApiBindHost(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("ApiBindHost", &Configuration::ApiBindHost, val, m_ReadOnly);
+}
+
+String Configuration::GetApiBindPort() const
+{
+	return Configuration::ApiBindPort;
+}
+
+void Configuration::SetApiBindPort(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("ApiBindPort", &Configuration::ApiBindPort, val, m_ReadOnly);
+}
+
+bool Configuration::GetAttachDebugger() const
+{
+	return Configuration::AttachDebugger;
+}
+
+void Configuration::SetAttachDebugger(bool val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("AttachDebugger", &Configuration::AttachDebugger, val, m_ReadOnly);
+}
+
+String Configuration::GetCacheDir() const
+{
+	return Configuration::CacheDir;
+}
+
+void Configuration::SetCacheDir(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("CacheDir", &Configuration::CacheDir, val, m_ReadOnly);
+}
+
+int Configuration::GetConcurrency() const
+{
+	return Configuration::Concurrency;
+}
+
+void Configuration::SetConcurrency(int val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("Concurrency", &Configuration::Concurrency, val, m_ReadOnly);
+}
+
+String Configuration::GetConfigDir() const
+{
+	return Configuration::ConfigDir;
+}
+
+void Configuration::SetConfigDir(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("ConfigDir", &Configuration::ConfigDir, val, m_ReadOnly);
+}
+
+String Configuration::GetDataDir() const
+{
+	return Configuration::DataDir;
+}
+
+void Configuration::SetDataDir(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("DataDir", &Configuration::DataDir, val, m_ReadOnly);
+}
+
+String Configuration::GetEventEngine() const
+{
+	return Configuration::EventEngine;
+}
+
+void Configuration::SetEventEngine(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("EventEngine", &Configuration::EventEngine, val, m_ReadOnly);
+}
+
+String Configuration::GetIncludeConfDir() const
+{
+	return Configuration::IncludeConfDir;
+}
+
+void Configuration::SetIncludeConfDir(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("IncludeConfDir", &Configuration::IncludeConfDir, val, m_ReadOnly);
+}
+
+String Configuration::GetInitRunDir() const
+{
+	return Configuration::InitRunDir;
+}
+
+void Configuration::SetInitRunDir(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("InitRunDir", &Configuration::InitRunDir, val, m_ReadOnly);
+}
+
+String Configuration::GetLogDir() const
+{
+	return Configuration::LogDir;
+}
+
+void Configuration::SetLogDir(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("LogDir", &Configuration::LogDir, val, m_ReadOnly);
+}
+
+String Configuration::GetModAttrPath() const
+{
+	return Configuration::ModAttrPath;
+}
+
+void Configuration::SetModAttrPath(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("ModAttrPath", &Configuration::ModAttrPath, val, m_ReadOnly);
+}
+
+String Configuration::GetObjectsPath() const
+{
+	return Configuration::ObjectsPath;
+}
+
+void Configuration::SetObjectsPath(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("ObjectsPath", &Configuration::ObjectsPath, val, m_ReadOnly);
+}
+
+String Configuration::GetPidPath() const
+{
+	return Configuration::PidPath;
+}
+
+void Configuration::SetPidPath(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("PidPath", &Configuration::PidPath, val, m_ReadOnly);
+}
+
+String Configuration::GetPkgDataDir() const
+{
+	return Configuration::PkgDataDir;
+}
+
+void Configuration::SetPkgDataDir(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("PkgDataDir", &Configuration::PkgDataDir, val, m_ReadOnly);
+}
+
+String Configuration::GetPrefixDir() const
+{
+	return Configuration::PrefixDir;
+}
+
+void Configuration::SetPrefixDir(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("PrefixDir", &Configuration::PrefixDir, val, m_ReadOnly);
+}
+
+String Configuration::GetProgramData() const
+{
+	return Configuration::ProgramData;
+}
+
+void Configuration::SetProgramData(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("ProgramData", &Configuration::ProgramData, val, m_ReadOnly);
+}
+
+int Configuration::GetRLimitFiles() const
+{
+	return Configuration::RLimitFiles;
+}
+
+void Configuration::SetRLimitFiles(int val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("RLimitFiles", &Configuration::RLimitFiles, val, m_ReadOnly);
+}
+
+int Configuration::GetRLimitProcesses() const
+{
+	return RLimitProcesses;
+}
+
+void Configuration::SetRLimitProcesses(int val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("RLimitProcesses", &Configuration::RLimitProcesses, val, m_ReadOnly);
+}
+
+int Configuration::GetRLimitStack() const
+{
+	return Configuration::RLimitStack;
+}
+
+void Configuration::SetRLimitStack(int val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("RLimitStack", &Configuration::RLimitStack, val, m_ReadOnly);
+}
+
+String Configuration::GetRunAsGroup() const
+{
+	return Configuration::RunAsGroup;
+}
+
+void Configuration::SetRunAsGroup(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("RunAsGroup", &Configuration::RunAsGroup, val, m_ReadOnly);
+}
+
+String Configuration::GetRunAsUser() const
+{
+	return Configuration::RunAsUser;
+}
+
+void Configuration::SetRunAsUser(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("RunAsUser", &Configuration::RunAsUser, val, m_ReadOnly);
+}
+
+String Configuration::GetSpoolDir() const
+{
+	return Configuration::SpoolDir;
+}
+
+void Configuration::SetSpoolDir(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("SpoolDir", &Configuration::SpoolDir, val, m_ReadOnly);
+}
+
+String Configuration::GetStatePath() const
+{
+	return Configuration::StatePath;
+}
+
+void Configuration::SetStatePath(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("StatePath", &Configuration::StatePath, val, m_ReadOnly);
+}
+
+String Configuration::GetVarsPath() const
+{
+	return Configuration::VarsPath;
+}
+
+void Configuration::SetVarsPath(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("VarsPath", &Configuration::VarsPath, val, m_ReadOnly);
+}
+
+String Configuration::GetZonesDir() const
+{
+	return Configuration::ZonesDir;
+}
+
+void Configuration::SetZonesDir(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("ZonesDir", &Configuration::ZonesDir, val, m_ReadOnly);
+}
+
+String Configuration::GetLocalStateDir() const
+{
+	return Configuration::LocalStateDir;
+}
+
+void Configuration::SetLocalStateDir(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("LocalStateDir", &Configuration::LocalStateDir, val, m_ReadOnly);
+}
+
+String Configuration::GetSysconfDir() const
+{
+	return Configuration::SysconfDir;
+}
+
+void Configuration::SetSysconfDir(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("SysconfDir", &Configuration::SysconfDir, val, m_ReadOnly);
+}
+
+String Configuration::GetRunDir() const
+{
+	return Configuration::RunDir;
+}
+
+void Configuration::SetRunDir(const String& val, bool suppress_events, const Value& cookie)
+{
+	HandleUserWrite("RunDir", &Configuration::RunDir, val, m_ReadOnly);
+}
+
+bool Configuration::GetReadOnly()
+{
+	return m_ReadOnly;
+}
+
+void Configuration::SetReadOnly(bool readOnly)
+{
+	m_ReadOnly = readOnly;
+}
diff --git a/lib/base/configuration.hpp b/lib/base/configuration.hpp
new file mode 100644
index 000000000..02a516b87
--- /dev/null
+++ b/lib/base/configuration.hpp
@@ -0,0 +1,169 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/)  *
+ *                                                                            *
+ * This program is free software; you can redistribute it and/or              *
+ * modify it under the terms of the GNU General Public License                *
+ * as published by the Free Software Foundation; either version 2             *
+ * of the License, or (at your option) any later version.                     *
+ *                                                                            *
+ * This program is distributed in the hope that it will be useful,            *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
+ * GNU General Public License for more details.                               *
+ *                                                                            *
+ * You should have received a copy of the GNU General Public License          *
+ * along with this program; if not, write to the Free Software Foundation     *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
+ ******************************************************************************/
+
+#ifndef CONFIGURATION_H
+#define CONFIGURATION_H
+
+#include "base/i2-base.hpp"
+#include "base/configuration-ti.hpp"
+
+namespace icinga
+{
+
+/**
+ * Global configuration.
+ *
+ * @ingroup base
+ */
+class Configuration : public ObjectImpl<Configuration>
+{
+public:
+	DECLARE_OBJECT(Configuration);
+
+	String GetApiBindHost() const override;
+	void SetApiBindHost(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetApiBindPort() const override;
+	void SetApiBindPort(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	bool GetAttachDebugger() const override;
+	void SetAttachDebugger(bool value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetCacheDir() const override;
+	void SetCacheDir(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	int GetConcurrency() const override;
+	void SetConcurrency(int value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetConfigDir() const override;
+	void SetConfigDir(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetDataDir() const override;
+	void SetDataDir(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetEventEngine() const override;
+	void SetEventEngine(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetIncludeConfDir() const override;
+	void SetIncludeConfDir(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetInitRunDir() const override;
+	void SetInitRunDir(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetLogDir() const override;
+	void SetLogDir(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetModAttrPath() const override;
+	void SetModAttrPath(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetObjectsPath() const override;
+	void SetObjectsPath(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetPidPath() const override;
+	void SetPidPath(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetPkgDataDir() const override;
+	void SetPkgDataDir(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetPrefixDir() const override;
+	void SetPrefixDir(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetProgramData() const override;
+	void SetProgramData(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	int GetRLimitFiles() const override;
+	void SetRLimitFiles(int value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	int GetRLimitProcesses() const override;
+	void SetRLimitProcesses(int value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	int GetRLimitStack() const override;
+	void SetRLimitStack(int value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetRunAsGroup() const override;
+	void SetRunAsGroup(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetRunAsUser() const override;
+	void SetRunAsUser(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetSpoolDir() const override;
+	void SetSpoolDir(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetStatePath() const override;
+	void SetStatePath(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetVarsPath() const override;
+	void SetVarsPath(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetZonesDir() const override;
+	void SetZonesDir(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	/* deprecated */
+	String GetLocalStateDir() const override;
+	void SetLocalStateDir(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetSysconfDir() const override;
+	void SetSysconfDir(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	String GetRunDir() const override;
+	void SetRunDir(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+
+	static bool GetReadOnly();
+	static void SetReadOnly(bool readOnly);
+
+	static String ApiBindHost;
+	static String ApiBindPort;
+	static bool AttachDebugger;
+	static String CacheDir;
+	static int Concurrency;
+	static String ConfigDir;
+	static String DataDir;
+	static String EventEngine;
+	static String IncludeConfDir;
+	static String InitRunDir;
+	static String LogDir;
+	static String ModAttrPath;
+	static String ObjectsPath;
+	static String PidPath;
+	static String PkgDataDir;
+	static String PrefixDir;
+	static String ProgramData;
+	static int RLimitFiles;
+	static int RLimitProcesses;
+	static int RLimitStack;
+	static String RunAsGroup;
+	static String RunAsUser;
+	static String SpoolDir;
+	static String StatePath;
+	static String VarsPath;
+	static String ZonesDir;
+
+	/* deprecated */
+	static String LocalStateDir;
+	static String RunDir;
+	static String SysconfDir;
+
+private:
+	static bool m_ReadOnly;
+
+};
+
+}
+
+#endif /* CONFIGURATION_H */
diff --git a/lib/base/configuration.ti b/lib/base/configuration.ti
new file mode 100644
index 000000000..abcba7d55
--- /dev/null
+++ b/lib/base/configuration.ti
@@ -0,0 +1,176 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/)  *
+ *                                                                            *
+ * This program is free software; you can redistribute it and/or              *
+ * modify it under the terms of the GNU General Public License                *
+ * as published by the Free Software Foundation; either version 2             *
+ * of the License, or (at your option) any later version.                     *
+ *                                                                            *
+ * This program is distributed in the hope that it will be useful,            *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
+ * GNU General Public License for more details.                               *
+ *                                                                            *
+ * You should have received a copy of the GNU General Public License          *
+ * along with this program; if not, write to the Free Software Foundation     *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
+ ******************************************************************************/
+
+#include "base/configobject.hpp"
+
+library base;
+
+namespace icinga
+{
+
+abstract class Configuration
+{
+	[config, no_storage, virtual] String ApiBindHost {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String ApiBindPort {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] bool AttachDebugger {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String CacheDir {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] int Concurrency {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String ConfigDir {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String DataDir {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String EventEngine {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String IncludeConfDir {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String InitRunDir {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String LogDir {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String ModAttrPath {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String ObjectsPath {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String PidPath {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String PkgDataDir {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String PrefixDir {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String ProgramData {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] int RLimitFiles {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] int RLimitProcesses {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] int RLimitStack {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String RunAsGroup {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String RunAsUser {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String SpoolDir {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String StatePath {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String VarsPath {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String ZonesDir {
+		get;
+		set;
+	};
+
+	/* deprecated */
+	[config, no_storage, virtual] String LocalStateDir {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String RunDir {
+		get;
+		set;
+	};
+
+	[config, no_storage, virtual] String SysconfDir {
+		get;
+		set;
+	};
+};
+
+}
diff --git a/lib/base/scriptframe.cpp b/lib/base/scriptframe.cpp
index 01f871ec4..90407613e 100644
--- a/lib/base/scriptframe.cpp
+++ b/lib/base/scriptframe.cpp
@@ -21,6 +21,7 @@
 #include "base/scriptglobal.hpp"
 #include "base/namespace.hpp"
 #include "base/exception.hpp"
+#include "base/configuration.hpp"
 
 using namespace icinga;
 
@@ -36,6 +37,8 @@ INITIALIZE_ONCE_WITH_PRIORITY([]() {
 	Namespace::Ptr systemNS = new Namespace(systemNSBehavior);
 	globalNS->SetAttribute("System", std::make_shared<ConstEmbeddedNamespaceValue>(systemNS));
 
+	systemNS->SetAttribute("Configuration", std::make_shared<EmbeddedNamespaceValue>(new Configuration()));
+
 	auto typesNSBehavior = new ConstNamespaceBehavior();
 	typesNSBehavior->Freeze();
 	Namespace::Ptr typesNS = new Namespace(typesNSBehavior);
diff --git a/lib/base/socketevents.cpp b/lib/base/socketevents.cpp
index e54ca0e6f..b967a345f 100644
--- a/lib/base/socketevents.cpp
+++ b/lib/base/socketevents.cpp
@@ -79,7 +79,7 @@ void SocketEventEngine::WakeUpThread(int sid, bool wait)
 
 void SocketEvents::InitializeEngine()
 {
-	String eventEngine = ScriptGlobal::Get("EventEngine", &Empty);
+	String eventEngine = Configuration::EventEngine;
 
 	if (eventEngine.IsEmpty())
 #ifdef __linux__
@@ -105,7 +105,7 @@ void SocketEvents::InitializeEngine()
 
 	l_SocketIOEngine->Start();
 
-	ScriptGlobal::Set("EventEngine", eventEngine);
+	Configuration::EventEngine = eventEngine;
 }
 
 /**
diff --git a/lib/base/tlsutility.cpp b/lib/base/tlsutility.cpp
index 42fc92921..66abf2b86 100644
--- a/lib/base/tlsutility.cpp
+++ b/lib/base/tlsutility.cpp
@@ -535,7 +535,7 @@ std::shared_ptr<X509> CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME
 
 String GetIcingaCADir()
 {
-	return Application::GetConst("DataDir") + "/ca";
+	return Configuration::DataDir + "/ca";
 }
 
 std::shared_ptr<X509> CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject)
diff --git a/lib/cli/apisetuputility.cpp b/lib/cli/apisetuputility.cpp
index a7739227c..640a878c9 100644
--- a/lib/cli/apisetuputility.cpp
+++ b/lib/cli/apisetuputility.cpp
@@ -40,7 +40,7 @@ using namespace icinga;
 
 String ApiSetupUtility::GetConfdPath()
 {
-	return Application::GetConst("ConfigDir") + "/conf.d";
+	return Configuration::ConfigDir + "/conf.d";
 }
 
 String ApiSetupUtility::GetApiUsersConfPath()
@@ -80,8 +80,8 @@ bool ApiSetupUtility::SetupMasterCertificates(const String& cn)
 	String pki_path = ApiListener::GetCertsDir();
 	Utility::MkDirP(pki_path, 0700);
 
-	String user = ScriptGlobal::Get("RunAsUser");
-	String group = ScriptGlobal::Get("RunAsGroup");
+	String user = Configuration::RunAsUser;
+	String group = Configuration::RunAsGroup;
 
 	if (!Utility::SetFileOwnership(pki_path, user, group)) {
 		Log(LogWarning, "cli")
diff --git a/lib/cli/daemoncommand.cpp b/lib/cli/daemoncommand.cpp
index ba20eb823..0cf7d3b91 100644
--- a/lib/cli/daemoncommand.cpp
+++ b/lib/cli/daemoncommand.cpp
@@ -72,7 +72,7 @@ static bool Daemonize()
 		do {
 			Utility::Sleep(0.1);
 
-			readpid = Application::ReadPidFile(Application::GetConst("PidPath"));
+			readpid = Application::ReadPidFile(Configuration::PidPath);
 			ret = waitpid(pid, &status, WNOHANG);
 		} while (readpid != pid && ret == 0);
 
@@ -193,7 +193,7 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::strin
 		<< ")";
 
 	if (!vm.count("validate") && !vm.count("reload-internal")) {
-		pid_t runningpid = Application::ReadPidFile(Application::GetConst("PidPath"));
+		pid_t runningpid = Application::ReadPidFile(Configuration::PidPath);
 		if (runningpid > 0) {
 			Log(LogCritical, "cli")
 				<< "Another instance of Icinga already running with PID " << runningpid;
@@ -206,7 +206,7 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::strin
 		configs = vm["config"].as<std::vector<std::string> >();
 	else if (!vm.count("no-config")) {
 		/* The implicit string assignment is needed for Windows builds. */
-		String configDir = Application::GetConst("ConfigDir");
+		String configDir = Configuration::ConfigDir;
 		configs.push_back(configDir + "/icinga2.conf");
 	}
 
@@ -214,7 +214,7 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::strin
 
 	std::vector<ConfigItem::Ptr> newItems;
 
-	if (!DaemonUtility::LoadConfigFiles(configs, newItems, Application::GetConst("ObjectsPath"), Application::GetConst("VarsPath")))
+	if (!DaemonUtility::LoadConfigFiles(configs, newItems, Configuration::ObjectsPath, Configuration::VarsPath))
 		return EXIT_FAILURE;
 
 	if (vm.count("validate")) {
@@ -256,7 +256,7 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::strin
 
 	/* restore the previous program state */
 	try {
-		ConfigObject::RestoreObjects(Application::GetConst("StatePath"));
+		ConfigObject::RestoreObjects(Configuration::StatePath);
 	} catch (const std::exception& ex) {
 		Log(LogCritical, "cli")
 			<< "Failed to restore state file: " << DiagnosticInformation(ex);
@@ -264,7 +264,7 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::strin
 	}
 
 	{
-		WorkQueue upq(25000, Application::GetConcurrency());
+		WorkQueue upq(25000, Configuration::Concurrency);
 		upq.SetName("DaemonCommand::Run");
 
 		// activate config only after daemonization: it starts threads and that is not compatible with fork()
diff --git a/lib/cli/daemonutility.cpp b/lib/cli/daemonutility.cpp
index 64d8b17c8..ea1630c8a 100644
--- a/lib/cli/daemonutility.cpp
+++ b/lib/cli/daemonutility.cpp
@@ -121,7 +121,7 @@ bool DaemonUtility::ValidateConfigFiles(const std::vector<std::string>& configs,
 	 * unfortunately moving it there is somewhat non-trivial. */
 	success = true;
 
-	String zonesEtcDir = Application::GetConst("ZonesDir");
+	String zonesEtcDir = Configuration::ZonesDir;
 	if (!zonesEtcDir.IsEmpty() && Utility::PathExists(zonesEtcDir))
 		Utility::Glob(zonesEtcDir + "/*", std::bind(&IncludeZoneDirRecursive, _1, "_etc", std::ref(success)), GlobDirectory);
 
@@ -130,7 +130,7 @@ bool DaemonUtility::ValidateConfigFiles(const std::vector<std::string>& configs,
 
 	/* Load package config files - they may contain additional zones which
 	 * are authoritative on this node and are checked in HasZoneConfigAuthority(). */
-	String packagesVarDir = Application::GetConst("DataDir") + "/api/packages";
+	String packagesVarDir = Configuration::DataDir + "/api/packages";
 	if (Utility::PathExists(packagesVarDir))
 		Utility::Glob(packagesVarDir + "/*", std::bind(&IncludePackage, _1, std::ref(success)), GlobDirectory);
 
@@ -138,7 +138,7 @@ bool DaemonUtility::ValidateConfigFiles(const std::vector<std::string>& configs,
 		return false;
 
 	/* Load cluster synchronized configuration files */
-	String zonesVarDir = Application::GetConst("DataDir") + "/api/zones";
+	String zonesVarDir = Configuration::DataDir + "/api/zones";
 	if (Utility::PathExists(zonesVarDir))
 		Utility::Glob(zonesVarDir + "/*", std::bind(&IncludeNonLocalZone, _1, "_cluster", std::ref(success)), GlobDirectory);
 
@@ -174,7 +174,7 @@ bool DaemonUtility::LoadConfigFiles(const std::vector<std::string>& configs,
 		return false;
 	}
 
-	WorkQueue upq(25000, Application::GetConcurrency());
+	WorkQueue upq(25000, Configuration::Concurrency);
 	upq.SetName("DaemonUtility::LoadConfigFiles");
 	bool result = ConfigItem::CommitItems(ascope.GetContext(), upq, newItems);
 
diff --git a/lib/cli/featureutility.cpp b/lib/cli/featureutility.cpp
index e01834c70..74c7a75bd 100644
--- a/lib/cli/featureutility.cpp
+++ b/lib/cli/featureutility.cpp
@@ -31,12 +31,12 @@ using namespace icinga;
 
 String FeatureUtility::GetFeaturesAvailablePath()
 {
-	return Application::GetConst("ConfigDir") + "/features-available";
+	return Configuration::ConfigDir + "/features-available";
 }
 
 String FeatureUtility::GetFeaturesEnabledPath()
 {
-	return Application::GetConst("ConfigDir") + "/features-enabled";
+	return Configuration::ConfigDir + "/features-enabled";
 }
 
 std::vector<String> FeatureUtility::GetFieldCompletionSuggestions(const String& word, bool enable)
diff --git a/lib/cli/nodesetupcommand.cpp b/lib/cli/nodesetupcommand.cpp
index 652f70f28..86581e6ea 100644
--- a/lib/cli/nodesetupcommand.cpp
+++ b/lib/cli/nodesetupcommand.cpp
@@ -353,8 +353,8 @@ int NodeSetupCommand::SetupNode(const boost::program_options::variables_map& vm,
 	String certsDir = ApiListener::GetCertsDir();
 	Utility::MkDirP(certsDir, 0700);
 
-	String user = ScriptGlobal::Get("RunAsUser");
-	String group = ScriptGlobal::Get("RunAsGroup");
+	String user = Configuration::RunAsUser;
+	String group = Configuration::RunAsGroup;
 
 	if (!Utility::SetFileOwnership(certsDir, user, group)) {
 		Log(LogWarning, "cli")
diff --git a/lib/cli/nodeutility.cpp b/lib/cli/nodeutility.cpp
index 259988259..101607fe0 100644
--- a/lib/cli/nodeutility.cpp
+++ b/lib/cli/nodeutility.cpp
@@ -43,12 +43,12 @@ using namespace icinga;
 
 String NodeUtility::GetConstantsConfPath()
 {
-	return Application::GetConst("ConfigDir") + "/constants.conf";
+	return Configuration::ConfigDir + "/constants.conf";
 }
 
 String NodeUtility::GetZonesConfPath()
 {
-	return Application::GetConst("ConfigDir") + "/zones.conf";
+	return Configuration::ConfigDir + "/zones.conf";
 }
 
 /*
@@ -170,8 +170,8 @@ bool NodeUtility::WriteNodeConfigObjects(const String& filename, const Array::Pt
 
 	Utility::MkDirP(path, 0755);
 
-	String user = ScriptGlobal::Get("RunAsUser");
-	String group = ScriptGlobal::Get("RunAsGroup");
+	String user = Configuration::RunAsUser;
+	String group = Configuration::RunAsGroup;
 
 	if (!Utility::SetFileOwnership(path, user, group)) {
 		Log(LogWarning, "cli")
@@ -274,7 +274,7 @@ void NodeUtility::SerializeObject(std::ostream& fp, const Dictionary::Ptr& objec
  */
 bool NodeUtility::UpdateConfiguration(const String& value, bool include, bool recursive)
 {
-	String configurationFile = Application::GetConst("ConfigDir") + "/icinga2.conf";
+	String configurationFile = Configuration::ConfigDir + "/icinga2.conf";
 
 	Log(LogInformation, "cli")
 		<< "Updating '" << value << "' include in '" << configurationFile << "'.";
diff --git a/lib/cli/nodewizardcommand.cpp b/lib/cli/nodewizardcommand.cpp
index 11e035aa7..96beba825 100644
--- a/lib/cli/nodewizardcommand.cpp
+++ b/lib/cli/nodewizardcommand.cpp
@@ -272,8 +272,8 @@ wizard_endpoint_loop_start:
 	String certsDir = ApiListener::GetCertsDir();
 	Utility::MkDirP(certsDir, 0700);
 
-	String user = ScriptGlobal::Get("RunAsUser");
-	String group = ScriptGlobal::Get("RunAsGroup");
+	String user = Configuration::RunAsUser;
+	String group = Configuration::RunAsGroup;
 
 	if (!Utility::SetFileOwnership(certsDir, user, group)) {
 		Log(LogWarning, "cli")
@@ -850,7 +850,7 @@ wizard_global_zone_loop_start:
 		}
 
 		/* Include api-users.conf */
-		String apiUsersFilePath = Application::GetConst("ConfigDir") + "/conf.d/api-users.conf";
+		String apiUsersFilePath = Configuration::ConfigDir + "/conf.d/api-users.conf";
 
 		std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundGreen)
 			<< "Checking if the api-users.conf file exists...\n"
diff --git a/lib/cli/objectlistcommand.cpp b/lib/cli/objectlistcommand.cpp
index f5c347eed..32495153a 100644
--- a/lib/cli/objectlistcommand.cpp
+++ b/lib/cli/objectlistcommand.cpp
@@ -67,11 +67,11 @@ void ObjectListCommand::InitParameters(boost::program_options::options_descripti
  */
 int ObjectListCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
 {
-	String objectfile = Application::GetConst("ObjectsPath");
+	String objectfile = Configuration::ObjectsPath;
 
 	if (!Utility::PathExists(objectfile)) {
 		Log(LogCritical, "cli")
-			<< "Cannot open objects file '" << Application::GetConst("ObjectsPath") << "'.";
+			<< "Cannot open objects file '" << Configuration::ObjectsPath << "'.";
 		Log(LogCritical, "cli", "Run 'icinga2 daemon -C' to validate config and generate the cache file.");
 		return 1;
 	}
diff --git a/lib/cli/troubleshootcommand.cpp b/lib/cli/troubleshootcommand.cpp
index 2770b5588..1e9892d9c 100644
--- a/lib/cli/troubleshootcommand.cpp
+++ b/lib/cli/troubleshootcommand.cpp
@@ -147,26 +147,26 @@ bool TroubleshootCommand::GeneralInfo(InfoLog& log, const boost::program_options
 
 	//Application::DisplayInfoMessage() but formatted
 	InfoLogLine(log)
-		<< "\tApplication version: " << Application::GetConst("AppVersion") << '\n'
+		<< "\tApplication version: " << Application::GetAppVersion() << '\n'
 		<< "\t\n"
-		<< "\tConfig directory: " << Application::GetConst("ConfigDir") << "\n"
-		<< "\tData directory: " << Application::GetConst("DataDir") << "\n"
-		<< "\tLog directory: " << Application::GetConst("LogDir") << "\n"
-		<< "\tCache directory: " << Application::GetConst("CacheDir") << "\n"
-		<< "\tRun directory: " << Application::GetConst("InitRunDir") << "\n"
+		<< "\tConfig directory: " << Configuration::ConfigDir << "\n"
+		<< "\tData directory: " << Configuration::DataDir << "\n"
+		<< "\tLog directory: " << Configuration::LogDir << "\n"
+		<< "\tCache directory: " << Configuration::CacheDir << "\n"
+		<< "\tRun directory: " << Configuration::InitRunDir << "\n"
 		<< "\t\n"
 		<< "Old paths (deprecated):\n"
-		<< "\tInstallation root: " << Application::GetConst("PrefixDir") << '\n'
-		<< "\tSysconf directory: " << Application::GetConst("SysconfDir") << '\n'
-		<< "\tRun directory: " << Application::GetConst("RunDir") << '\n'
-		<< "\tLocal state directory: " << Application::GetConst("LocalStateDir") << '\n'
+		<< "\tInstallation root: " << Configuration::PrefixDir << '\n'
+		<< "\tSysconf directory: " << Configuration::SysconfDir << '\n'
+		<< "\tRun directory: " << Configuration::RunDir << '\n'
+		<< "\tLocal state directory: " << Configuration::LocalStateDir << '\n'
 		<< "\t\n"
 		<< "Internal paths:\n"
-		<< "\tPackage data directory: " << Application::GetConst("PkgDataDir") << '\n'
-		<< "\tState path: " << Application::GetConst("StatePath") << '\n'
-		<< "\tObjects path: " << Application::GetConst("ObjectsPath") << '\n'
-		<< "\tVars path: " << Application::GetConst("VarsPath") << '\n'
-		<< "\tPID path: " << Application::GetConst("PidPath") << '\n';
+		<< "\tPackage data directory: " << Configuration::PkgDataDir << '\n'
+		<< "\tState path: " << Configuration::StatePath << '\n'
+		<< "\tObjects path: " << Configuration::ObjectsPath << '\n'
+		<< "\tVars path: " << Configuration::VarsPath << '\n'
+		<< "\tPID path: " << Configuration::PidPath << '\n';
 
 	InfoLogLine(log)
 		<< '\n';
@@ -186,7 +186,7 @@ bool TroubleshootCommand::ObjectInfo(InfoLog& log, const boost::program_options:
 	InfoLogLine(log, Console_ForegroundBlue)
 		<< std::string(14, '=') << " OBJECT INFORMATION " << std::string(14, '=') << "\n\n";
 
-	String objectfile = Application::GetConst("ObjectsPath");
+	String objectfile = Configuration::ObjectsPath;
 	std::set<String> configs;
 
 	if (!Utility::PathExists(objectfile)) {
@@ -262,14 +262,14 @@ bool TroubleshootCommand::ConfigInfo(InfoLog& log, const boost::program_options:
 	InfoLogLine(log)
 		<< "A collection of important configuration files follows, please make sure to remove any sensitive data such as credentials, internal company names, etc\n";
 
-	if (!PrintFile(log, Application::GetConst("ConfigDir") + "/icinga2.conf")) {
+	if (!PrintFile(log, Configuration::ConfigDir + "/icinga2.conf")) {
 		InfoLogLine(log, 0, LogWarning)
 			<< "icinga2.conf not found, therefore skipping validation.\n"
 			<< "If you are using an icinga2.conf somewhere but the default path please validate it via 'icinga2 daemon -C -c \"path\to/icinga2.conf\"'\n"
 			<< "and provide it with your support request.\n";
 	}
 
-	if (!PrintFile(log, Application::GetConst("ConfigDir") + "/zones.conf")) {
+	if (!PrintFile(log, Configuration::ConfigDir + "/zones.conf")) {
 		InfoLogLine(log, 0, LogWarning)
 			<< "zones.conf not found.\n"
 			<< "If you are using a zones.conf somewhere but the default path please provide it with your support request\n";
@@ -380,7 +380,7 @@ void TroubleshootCommand::GetLatestReport(const String& filename, time_t& bestTi
 
 bool TroubleshootCommand::PrintCrashReports(InfoLog& log)
 {
-	String spath = Application::GetConst("LogDir") + "/crash/report.*";
+	String spath = Configuration::LogDir + "/crash/report.*";
 	time_t bestTimestamp = 0;
 	String bestFilename;
 
@@ -393,7 +393,7 @@ bool TroubleshootCommand::PrintCrashReports(InfoLog& log)
 		if (int const * err = boost::get_error_info<errinfo_win32_error>(ex)) {
 			if (*err != 3) {//Error code for path does not exist
 				InfoLogLine(log, 0, LogWarning)
-					<< Application::GetConst("LogDir") + "/crash/ does not exist\n";
+					<< Configuration::LogDir + "/crash/ does not exist\n";
 
 				return false;
 			}
@@ -406,7 +406,7 @@ bool TroubleshootCommand::PrintCrashReports(InfoLog& log)
 #else
 	catch (...) {
 		InfoLogLine(log, 0, LogWarning) << "Error printing crash reports.\n"
-			<< "Does " << Application::GetConst("LogDir") + "/crash/ exist?\n";
+			<< "Does " << Configuration::LogDir + "/crash/ exist?\n";
 
 		return false;
 	}
@@ -414,7 +414,7 @@ bool TroubleshootCommand::PrintCrashReports(InfoLog& log)
 
 	if (!bestTimestamp)
 		InfoLogLine(log, Console_ForegroundYellow)
-			<< "No crash logs found in " << Application::GetConst("LogDir") << "/crash/\n\n";
+			<< "No crash logs found in " << Configuration::LogDir << "/crash/\n\n";
 	else {
 		InfoLogLine(log)
 			<< "Latest crash report is from " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", Utility::GetTime()) << '\n'
@@ -454,8 +454,8 @@ bool TroubleshootCommand::PrintFile(InfoLog& log, const String& path)
 
 bool TroubleshootCommand::CheckConfig()
 {
-	String configDir = Application::GetConst("ConfigDir");
-	String objectsPath = Application::GetConst("ObjectsPath");
+	String configDir = Configuration::ConfigDir;
+	String objectsPath = Configuration::ObjectsPath;
 	return DaemonUtility::ValidateConfigFiles({ configDir + "/icinga2.conf" }, objectsPath);
 }
 
@@ -622,10 +622,10 @@ void TroubleshootCommand::InitParameters(boost::program_options::options_descrip
 int TroubleshootCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
 {
 #ifdef _WIN32 //Dislikes ':' in filenames
-	String path = Application::GetConst("LogDir") + "/troubleshooting-"
+	String path = Configuration::LogDir + "/troubleshooting-"
 		+ Utility::FormatDateTime("%Y-%m-%d_%H-%M-%S", Utility::GetTime()) + ".log";
 #else
-	String path = Application::GetConst("LogDir") + "/troubleshooting-"
+	String path = Configuration::LogDir + "/troubleshooting-"
 		+ Utility::FormatDateTime("%Y-%m-%d_%H:%M:%S", Utility::GetTime()) + ".log";
 #endif /*_WIN32*/
 
diff --git a/lib/cli/variablegetcommand.cpp b/lib/cli/variablegetcommand.cpp
index 855770148..72e5b58b4 100644
--- a/lib/cli/variablegetcommand.cpp
+++ b/lib/cli/variablegetcommand.cpp
@@ -75,7 +75,7 @@ int VariableGetCommand::Run(const boost::program_options::variables_map& vm, con
 		return 0;
 	}
 
-	String varsfile = Application::GetConst("VarsPath");
+	String varsfile = Configuration::VarsPath;
 
 	if (!Utility::PathExists(varsfile)) {
 		Log(LogCritical, "cli")
diff --git a/lib/cli/variablelistcommand.cpp b/lib/cli/variablelistcommand.cpp
index 9ebbadf11..612f912f8 100644
--- a/lib/cli/variablelistcommand.cpp
+++ b/lib/cli/variablelistcommand.cpp
@@ -53,7 +53,7 @@ String VariableListCommand::GetShortDescription() const
  */
 int VariableListCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
 {
-	String varsfile = Application::GetConst("VarsPath");
+	String varsfile = Configuration::VarsPath;
 
 	if (!Utility::PathExists(varsfile)) {
 		Log(LogCritical, "cli")
diff --git a/lib/cli/variableutility.cpp b/lib/cli/variableutility.cpp
index ed9bd770d..1c03f25d7 100644
--- a/lib/cli/variableutility.cpp
+++ b/lib/cli/variableutility.cpp
@@ -31,7 +31,7 @@ using namespace icinga;
 
 Value VariableUtility::GetVariable(const String& name)
 {
-	String varsfile = Application::GetConst("VarsPath");
+	String varsfile = Configuration::VarsPath;
 
 	std::fstream fp;
 	fp.open(varsfile.CStr(), std::ios_base::in);
@@ -61,7 +61,7 @@ Value VariableUtility::GetVariable(const String& name)
 
 void VariableUtility::PrintVariables(std::ostream& outfp)
 {
-	String varsfile = Application::GetConst("VarsPath");
+	String varsfile = Configuration::VarsPath;
 
 	std::fstream fp;
 	fp.open(varsfile.CStr(), std::ios_base::in);
diff --git a/lib/compat/checkresultreader.ti b/lib/compat/checkresultreader.ti
index cc558a553..1f97c22fd 100644
--- a/lib/compat/checkresultreader.ti
+++ b/lib/compat/checkresultreader.ti
@@ -30,7 +30,7 @@ class CheckResultReader : ConfigObject
 	activation_priority 100;
 
 	[config] String spool_dir {
-		default {{{ return Application::GetConst("DataDir") + "/spool/checkresults/"; }}}
+		default {{{ return Configuration::DataDir + "/spool/checkresults/"; }}}
 	};
 };
 
diff --git a/lib/compat/compatlogger.ti b/lib/compat/compatlogger.ti
index 4066a72bd..0ea63ad1d 100644
--- a/lib/compat/compatlogger.ti
+++ b/lib/compat/compatlogger.ti
@@ -30,7 +30,7 @@ class CompatLogger : ConfigObject
 	activation_priority 100;
 
 	[config] String log_dir {
-		default {{{ return Application::GetConst("LogDir") + "/compat"; }}}
+		default {{{ return Configuration::LogDir + "/compat"; }}}
 	};
 	[config] String rotation_method {
 		default {{{ return "HOURLY"; }}}
diff --git a/lib/compat/externalcommandlistener.ti b/lib/compat/externalcommandlistener.ti
index 697b3a0c4..8ff99a5d3 100644
--- a/lib/compat/externalcommandlistener.ti
+++ b/lib/compat/externalcommandlistener.ti
@@ -30,7 +30,7 @@ class ExternalCommandListener : ConfigObject
 	activation_priority 100;
 
 	[config] String command_path {
-		default {{{ return Application::GetConst("InitRunDir") + "/cmd/icinga2.cmd"; }}}
+		default {{{ return Configuration::InitRunDir + "/cmd/icinga2.cmd"; }}}
 	};
 };
 
diff --git a/lib/compat/statusdatawriter.cpp b/lib/compat/statusdatawriter.cpp
index e5a4578ac..b2b8ce376 100644
--- a/lib/compat/statusdatawriter.cpp
+++ b/lib/compat/statusdatawriter.cpp
@@ -559,7 +559,7 @@ void StatusDataWriter::UpdateObjectsCache()
 {
 	CONTEXT("Writing objects.cache file");
 
-	String objectsPath = Application::GetConst("ObjectsPath");
+	String objectsPath = Configuration::ObjectsPath;
 
 	std::fstream objectfp;
 	String tempObjectsPath = Utility::CreateTempFile(objectsPath + ".XXXXXX", 0644, objectfp);
diff --git a/lib/compat/statusdatawriter.ti b/lib/compat/statusdatawriter.ti
index 846834f31..db81940ed 100644
--- a/lib/compat/statusdatawriter.ti
+++ b/lib/compat/statusdatawriter.ti
@@ -30,10 +30,10 @@ class StatusDataWriter : ConfigObject
 	activation_priority 100;
 
 	[config] String status_path {
-		default {{{ return Application::GetConst("CacheDir") + "/status.dat"; }}}
+		default {{{ return Configuration::CacheDir + "/status.dat"; }}}
 	};
 	[config] String objects_path {
-		default {{{ return Application::GetConst("CacheDir") + "/objects.cache"; }}}
+		default {{{ return Configuration::CacheDir + "/objects.cache"; }}}
 	};
 	[config] double update_interval {
 		default {{{ return 15; }}}
diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp
index 53c889b4d..47b7e327c 100644
--- a/lib/config/configitem.cpp
+++ b/lib/config/configitem.cpp
@@ -577,8 +577,8 @@ bool ConfigItem::ActivateItems(WorkQueue& upq, const std::vector<ConfigItem::Ptr
 
 	if (withModAttrs) {
 		/* restore modified attributes */
-		if (Utility::PathExists(Application::GetConst("ModAttrPath"))) {
-			std::unique_ptr<Expression> expression = ConfigCompiler::CompileFile(Application::GetConst("ModAttrPath"));
+		if (Utility::PathExists(Configuration::ModAttrPath)) {
+			std::unique_ptr<Expression> expression = ConfigCompiler::CompileFile(Configuration::ModAttrPath);
 
 			if (expression) {
 				try {
@@ -675,7 +675,7 @@ bool ConfigItem::RunWithActivationContext(const Function::Ptr& function)
 
 	function->Invoke();
 
-	WorkQueue upq(25000, Application::GetConcurrency());
+	WorkQueue upq(25000, Configuration::Concurrency);
 	upq.SetName("ConfigItem::RunWithActivationContext");
 
 	std::vector<ConfigItem::Ptr> newItems;
diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp
index 7600b130e..e3910488e 100644
--- a/lib/config/expression.cpp
+++ b/lib/config/expression.cpp
@@ -121,6 +121,7 @@ VariableExpression::VariableExpression(String variable, std::vector<std::shared_
 	: DebuggableExpression(debugInfo), m_Variable(std::move(variable)), m_Imports(std::move(imports))
 {
 	m_Imports.push_back(MakeIndexer(ScopeGlobal, "System"));
+	m_Imports.push_back(std::unique_ptr<Expression>(new IndexerExpression(MakeIndexer(ScopeGlobal, "System"), MakeLiteral("Configuration"))));
 	m_Imports.push_back(MakeIndexer(ScopeGlobal, "Types"));
 	m_Imports.push_back(MakeIndexer(ScopeGlobal, "Icinga"));
 }
diff --git a/lib/icinga/icingaapplication.cpp b/lib/icinga/icingaapplication.cpp
index fab5187a6..28ca04bbd 100644
--- a/lib/icinga/icingaapplication.cpp
+++ b/lib/icinga/icingaapplication.cpp
@@ -163,13 +163,13 @@ static void PersistModAttrHelper(std::fstream& fp, ConfigObject::Ptr& previousOb
 
 void IcingaApplication::DumpProgramState()
 {
-	ConfigObject::DumpObjects(GetConst("StatePath"));
+	ConfigObject::DumpObjects(Configuration::StatePath);
 	DumpModifiedAttributes();
 }
 
 void IcingaApplication::DumpModifiedAttributes()
 {
-	String path = GetConst("ModAttrPath");
+	String path = Configuration::ModAttrPath;
 
 	std::fstream fp;
 	String tempFilename = Utility::CreateTempFile(path + ".XXXXXX", 0644, fp);
diff --git a/lib/livestatus/livestatuslistener.ti b/lib/livestatus/livestatuslistener.ti
index 1a4729d5e..5c886176e 100644
--- a/lib/livestatus/livestatuslistener.ti
+++ b/lib/livestatus/livestatuslistener.ti
@@ -32,7 +32,7 @@ class LivestatusListener : ConfigObject {
 		default {{{ return "unix"; }}}
 	};
 	[config] String socket_path {
-		default {{{ return Application::GetConst("InitRunDir") + "/cmd/livestatus"; }}}
+		default {{{ return Configuration::InitRunDir + "/cmd/livestatus"; }}}
 	};
 	[config] String bind_host {
 		default {{{ return "127.0.0.1"; }}}
@@ -41,7 +41,7 @@ class LivestatusListener : ConfigObject {
 		default {{{ return "6558"; }}}
 	};
 	[config] String compat_log_path {
-		default {{{ return Application::GetConst("LogDir") + "/compat"; }}}
+		default {{{ return Configuration::LogDir + "/compat"; }}}
 	};
 };
 
diff --git a/lib/perfdata/perfdatawriter.ti b/lib/perfdata/perfdatawriter.ti
index 4b6560291..ab0a2b6d6 100644
--- a/lib/perfdata/perfdatawriter.ti
+++ b/lib/perfdata/perfdatawriter.ti
@@ -30,16 +30,16 @@ class PerfdataWriter : ConfigObject
 	activation_priority 100;
 
 	[config] String host_perfdata_path {
-		default {{{ return Application::GetConst("SpoolDir") + "/perfdata/host-perfdata"; }}}
+		default {{{ return Configuration::SpoolDir + "/perfdata/host-perfdata"; }}}
 	};
 	[config] String service_perfdata_path {
-		default {{{ return Application::GetConst("SpoolDir") + "/perfdata/service-perfdata"; }}}
+		default {{{ return Configuration::SpoolDir + "/perfdata/service-perfdata"; }}}
 	};
 	[config] String host_temp_path {
-		default {{{ return Application::GetConst("SpoolDir") + "/tmp/host-perfdata"; }}}
+		default {{{ return Configuration::SpoolDir + "/tmp/host-perfdata"; }}}
 	};
 	[config] String service_temp_path {
-		default {{{ return Application::GetConst("SpoolDir") + "/tmp/service-perfdata"; }}}
+		default {{{ return Configuration::SpoolDir + "/tmp/service-perfdata"; }}}
 	};
 	[config] String host_format_template {
 		default {{{
diff --git a/lib/remote/apilistener-filesync.cpp b/lib/remote/apilistener-filesync.cpp
index 0c8987237..5d3c1ddb9 100644
--- a/lib/remote/apilistener-filesync.cpp
+++ b/lib/remote/apilistener-filesync.cpp
@@ -202,7 +202,7 @@ void ApiListener::SyncZoneDir(const Zone::Ptr& zone) const
 	if (sumUpdates == 0)
 		return;
 
-	String oldDir = Application::GetConst("DataDir") + "/api/zones/" + zone->GetName();
+	String oldDir = Configuration::DataDir + "/api/zones/" + zone->GetName();
 
 	Log(LogInformation, "ApiListener")
 		<< "Copying " << sumUpdates << " zone configuration files for zone '" << zone->GetName() << "' to '" << oldDir << "'.";
@@ -240,7 +240,7 @@ void ApiListener::SendConfigUpdate(const JsonRpcConnection::Ptr& aclient)
 	Dictionary::Ptr configUpdateV1 = new Dictionary();
 	Dictionary::Ptr configUpdateV2 = new Dictionary();
 
-	String zonesDir = Application::GetConst("DataDir") + "/api/zones";
+	String zonesDir = Configuration::DataDir + "/api/zones";
 
 	for (const Zone::Ptr& zone : ConfigType::GetObjectsByType<Zone>()) {
 		String zoneDir = zonesDir + "/" + zone->GetName();
@@ -315,7 +315,7 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D
 			continue;
 		}
 
-		String oldDir = Application::GetConst("DataDir") + "/api/zones/" + zone->GetName();
+		String oldDir = Configuration::DataDir + "/api/zones/" + zone->GetName();
 
 		Utility::MkDirP(oldDir, 0700);
 
diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp
index 8c0abf570..4dd914470 100644
--- a/lib/remote/apilistener.cpp
+++ b/lib/remote/apilistener.cpp
@@ -56,22 +56,22 @@ ApiListener::ApiListener()
 
 String ApiListener::GetApiDir()
 {
-	return Application::GetConst("DataDir") + "/api/";
+	return Configuration::DataDir + "/api/";
 }
 
 String ApiListener::GetCertsDir()
 {
-	return Application::GetConst("DataDir") + "/certs/";
+	return Configuration::DataDir + "/certs/";
 }
 
 String ApiListener::GetCaDir()
 {
-	return Application::GetConst("DataDir") + "/ca/";
+	return Configuration::DataDir + "/ca/";
 }
 
 String ApiListener::GetCertificateRequestsDir()
 {
-	return Application::GetConst("DataDir") + "/certificate-requests/";
+	return Configuration::DataDir + "/certificate-requests/";
 }
 
 String ApiListener::GetDefaultCertPath()
@@ -1479,7 +1479,7 @@ String ApiListener::GetFromZoneName(const Zone::Ptr& fromZone)
 
 void ApiListener::UpdateStatusFile(TcpSocket::Ptr socket)
 {
-	String path = Application::GetConst("CacheDir") + "/api-state.json";
+	String path = Configuration::CacheDir + "/api-state.json";
 	std::pair<String, String> details = socket->GetClientAddressDetails();
 
 	Utility::SaveJsonFile(path, 0644, new Dictionary({
@@ -1490,7 +1490,7 @@ void ApiListener::UpdateStatusFile(TcpSocket::Ptr socket)
 
 void ApiListener::RemoveStatusFile()
 {
-	String path = Application::GetConst("CacheDir") + "/api-state.json";
+	String path = Configuration::CacheDir + "/api-state.json";
 
 	if (Utility::PathExists(path)) {
 		if (unlink(path.CStr()) < 0 && errno != ENOENT) {
diff --git a/lib/remote/apilistener.ti b/lib/remote/apilistener.ti
index 04e483270..e4227a6d1 100644
--- a/lib/remote/apilistener.ti
+++ b/lib/remote/apilistener.ti
@@ -42,10 +42,10 @@ class ApiListener : ConfigObject
 	};
 
 	[config] String bind_host {
-		default {{{ return Application::GetConst("ApiBindHost"); }}}
+		default {{{ return Configuration::ApiBindHost; }}}
 	};
 	[config] String bind_port {
-		default {{{ return Application::GetConst("ApiBindPort", "5665"); }}}
+		default {{{ return Configuration::ApiBindPort; }}}
 	};
 
 	[config] bool accept_config;
diff --git a/lib/remote/configpackageutility.cpp b/lib/remote/configpackageutility.cpp
index 19b1022e8..34620e1db 100644
--- a/lib/remote/configpackageutility.cpp
+++ b/lib/remote/configpackageutility.cpp
@@ -30,7 +30,7 @@ using namespace icinga;
 
 String ConfigPackageUtility::GetPackageDir()
 {
-	return Application::GetConst("DataDir") + "/api/packages";
+	return Configuration::DataDir + "/api/packages";
 }
 
 void ConfigPackageUtility::CreatePackage(const String& name)
diff --git a/lib/remote/consolehandler.cpp b/lib/remote/consolehandler.cpp
index aff47a9a9..22b49d4b7 100644
--- a/lib/remote/consolehandler.cpp
+++ b/lib/remote/consolehandler.cpp
@@ -290,7 +290,10 @@ std::vector<String> ConsoleHandler::GetAutocompletionSuggestions(const String& w
 		}
 	}
 
-	AddSuggestions(matches, word, "", false, ScriptGlobal::Get("System"));
+	Namespace::Ptr systemNS = ScriptGlobal::Get("System");
+
+	AddSuggestions(matches, word, "", false, systemNS);
+	AddSuggestions(matches, word, "", true, systemNS->Get("Configuration"));
 	AddSuggestions(matches, word, "", false, ScriptGlobal::Get("Types"));
 	AddSuggestions(matches, word, "", false, ScriptGlobal::Get("Icinga"));
 
diff --git a/lib/remote/jsonrpcconnection.cpp b/lib/remote/jsonrpcconnection.cpp
index 259679edc..0022d5072 100644
--- a/lib/remote/jsonrpcconnection.cpp
+++ b/lib/remote/jsonrpcconnection.cpp
@@ -59,7 +59,7 @@ void JsonRpcConnection::StaticInitialize()
 	l_JsonRpcConnectionTimeoutTimer->SetInterval(15);
 	l_JsonRpcConnectionTimeoutTimer->Start();
 
-	l_JsonRpcConnectionWorkQueueCount = Application::GetConcurrency();
+	l_JsonRpcConnectionWorkQueueCount = Configuration::Concurrency;
 	l_JsonRpcConnectionWorkQueues = new WorkQueue[l_JsonRpcConnectionWorkQueueCount];
 
 	for (size_t i = 0; i < l_JsonRpcConnectionWorkQueueCount; i++) {