diff --git a/bundles/org.eclipse.equinox.preferences.tests/src/org/eclipse/equinox/preferences/tests/ScopeStorageLocationTest.java b/bundles/org.eclipse.equinox.preferences.tests/src/org/eclipse/equinox/preferences/tests/ScopeStorageLocationTest.java
new file mode 100644
index 00000000000..03374269dc4
--- /dev/null
+++ b/bundles/org.eclipse.equinox.preferences.tests/src/org/eclipse/equinox/preferences/tests/ScopeStorageLocationTest.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2024,2024 Hannes Wellmann and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Hannes Wellmann - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.preferences.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.ConfigurationScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.core.runtime.preferences.UserScope;
+import org.junit.Test;
+import org.osgi.service.prefs.BackingStoreException;
+
+public class ScopeStorageLocationTest {
+
+	@Test
+	public void testInstanceScope_writeLocation() throws Exception {
+		Path instanceLocation = getInstancePreferenceLocation();
+		assertWriteLocation(InstanceScope.INSTANCE, instanceLocation);
+	}
+
+	@Test
+	public void testInstanceScope_readLocation() throws Exception {
+		Path instanceLocation = getInstancePreferenceLocation();
+		assertReadLocation(InstanceScope.INSTANCE, instanceLocation);
+	}
+
+	private static Path getInstancePreferenceLocation() throws URISyntaxException {
+		return Path.of(Platform.getInstanceLocation().getURL().toURI())
+				.resolve(".metadata/.plugins/org.eclipse.core.runtime/");
+	}
+
+	@Test
+	public void testConfigurationScope_writeLocation() throws Exception {
+		Path configurationLocation = getConfigurationPreferenceLocation();
+		assertWriteLocation(ConfigurationScope.INSTANCE, configurationLocation);
+	}
+
+	@Test
+	public void testConfigurationScope_readLocation() throws Exception {
+		Path configurationLocation = getConfigurationPreferenceLocation();
+		assertReadLocation(ConfigurationScope.INSTANCE, configurationLocation);
+	}
+
+	private static Path getConfigurationPreferenceLocation() throws URISyntaxException {
+		return Path.of(Platform.getConfigurationLocation().getURL().toURI());
+	}
+
+	@Test
+	public void testUserScope_writeLocation() throws Exception {
+		Path configurationLocation = getUserPreferenenceLocation();
+		assertWriteLocation(UserScope.INSTANCE, configurationLocation);
+	}
+
+	@Test
+	public void testUserScope_readLocation() throws Exception {
+		Path configurationLocation = getUserPreferenenceLocation();
+		assertReadLocation(UserScope.INSTANCE, configurationLocation);
+	}
+
+	private static Path getUserPreferenenceLocation() {
+		return Path.of(System.getProperty("user.home") + "/.eclipse");
+	}
+
+	private static void assertWriteLocation(IScopeContext scope, Path expectedPreferenceLocation)
+			throws BackingStoreException, IOException {
+		Path expectedFileLocation = expectedPreferenceLocation.resolve(".settings/foo.bar.prefs");
+		assertFalse(Files.exists(expectedFileLocation));
+		try {
+			IEclipsePreferences node = scope.getNode("foo.bar");
+			node.putInt("someCount", 5);
+			node.flush();
+			String preferenceFileContent = Files.readString(expectedFileLocation);
+			assertEquals("""
+					eclipse.preferences.version=1
+					someCount=5
+					""".replace("\n", System.lineSeparator()), preferenceFileContent);
+		} finally {
+			Files.deleteIfExists(expectedFileLocation);
+		}
+	}
+
+	private static void assertReadLocation(IScopeContext scope, Path expectedPreferenceLocation)
+			throws BackingStoreException, IOException {
+		Path expectedFileLocation = expectedPreferenceLocation.resolve(".settings/foo.bar.buzz.prefs");
+		assertFalse(Files.exists(expectedFileLocation));
+		try {
+			Files.createDirectories(expectedFileLocation.getParent());
+			Files.writeString(expectedFileLocation, """
+					eclipse.preferences.version=1
+					aSetting=HelloWorld
+					""");
+			assertEquals("HelloWorld", scope.getNode("foo.bar.buzz").get("aSetting", null));
+		} finally {
+			Files.deleteIfExists(expectedFileLocation);
+		}
+
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesService.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesService.java
index 35049cb84a2..9c43eb7e4e6 100644
--- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesService.java
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesService.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2023 IBM Corporation and others.
+ * Copyright (c) 2004, 2024 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -39,6 +39,7 @@ public class PreferencesService implements IPreferencesService {
 	private static List<String> DEFAULT_DEFAULT_LOOKUP_ORDER = List.of( //
 			InstanceScope.SCOPE, //
 			ConfigurationScope.SCOPE, //
+			UserScope.SCOPE, //
 			DefaultScope.SCOPE);
 	private static final char EXPORT_ROOT_PREFIX = '!';
 	private static final char BUNDLE_VERSION_PREFIX = '@';
@@ -67,6 +68,7 @@ private PreferencesService() {
 		initializeDefaultScope(DefaultScope.SCOPE, new DefaultPreferences());
 		initializeDefaultScope(InstanceScope.SCOPE, new InstancePreferences());
 		initializeDefaultScope(ConfigurationScope.SCOPE, new ConfigurationPreferences());
+		initializeDefaultScope(UserScope.SCOPE, new UserPreferences());
 	}
 
 	@Override
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/UserPreferences.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/UserPreferences.java
new file mode 100644
index 00000000000..ec24290a7f8
--- /dev/null
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/UserPreferences.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2023, 2024 Hannes Wellmann and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Hannes Wellmann - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.core.internal.preferences;
+
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.preferences.UserScope;
+
+public class UserPreferences extends SingletonEclipsePreferences {
+
+	// cache which nodes have been loaded from disk
+	private static final Set<String> LOADED_NODES = ConcurrentHashMap.newKeySet();
+	private static final AtomicBoolean INITIALIZED = new AtomicBoolean();
+
+	/**
+	 * Default constructor. Should only be called by #createExecutableExtension.
+	 */
+	public UserPreferences() {
+		this(null, null);
+	}
+
+	private UserPreferences(EclipsePreferences parent, String name) {
+		super(parent, name, LOADED_NODES, INITIALIZED);
+	}
+
+	@Override
+	IPath getBaseLocation() {
+		return UserScope.INSTANCE.getLocation();
+	}
+
+	@Override
+	protected EclipsePreferences internalCreate(EclipsePreferences nodeParent, String nodeName, Object context) {
+		return new UserPreferences(nodeParent, nodeName);
+	}
+}
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/runtime/preferences/UserScope.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/runtime/preferences/UserScope.java
new file mode 100644
index 00000000000..d745159c6b0
--- /dev/null
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/runtime/preferences/UserScope.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2023, 2024 Hannes Wellmann and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Hannes Wellmann - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.core.runtime.preferences;
+
+import org.eclipse.core.internal.preferences.AbstractScope;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * @since 3.11
+ */
+public class UserScope extends AbstractScope {
+
+	/**
+	 * String constant (value of <code>"user"</code>) used for the scope name for
+	 * the user preference scope.
+	 */
+	public static final String SCOPE = "user"; //$NON-NLS-1$
+
+	private static final IPath USER_HOME_PREFERENCE_LOCATION;
+	static {
+		String userHome = System.getProperty("user.home"); //$NON-NLS-1$
+		USER_HOME_PREFERENCE_LOCATION = IPath.forWindows(userHome).append(".eclipse"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Singleton instance of a User Scope object. Typical usage is:
+	 * <code>UserScope.INSTANCE.getNode(...);</code>
+	 *
+	 * @since 3.4
+	 */
+	public static final IScopeContext INSTANCE = new UserScope();
+
+	private UserScope() { // static use only via INSTANCE
+	}
+
+	@Override
+	public String getName() {
+		return SCOPE;
+	}
+
+	@Override
+	public IPath getLocation() {
+		return USER_HOME_PREFERENCE_LOCATION;
+	}
+
+}