Repository: graphhopper/graphhopper
Pull request #1958 (2020-03-17 19:13:49)

Move ProfileResolver out of GraphHopper class
In this PR I moved the `ProfileResolver` out of `GraphHopper` and into the `Route/Isochrone/SPTResource`. This means:

* `GraphHopper#route` only considers the `profile` parameter (instead of `vehicle,weighting,edge_based`). At the moment it even throws an error if these parameters are set. Is that ok or should we go for a 'softer' migration and change this to an error log only? A missing `profile` parameter is definitely an error, I just wonder if its too strict to throw an error in case there is also `vehicle/weighting` (which are not used anyway). 

* To make use of the `profile` parameter we now have to add routing profiles also for non-prepared (no CH or LM) algorithms. GH configs without profiles lead to an error with this PR!

* `ProfileResolver` does the conversion of the `vehicle/weighting/edge_based` parameters and the profile name is passed to `GraphHopper`. Therefore the actual behavior of the GH server should not be changed (unless there is a bug). 

Another change that is done here is that we no longer use the first flag encoder as default vehicle. We already did this for CH before, but now its the same for CH/LM/flex. If the vehicle parameter is not set (and ch.disable=true) we are trying to find a matching profile based on the other parameters. If there are multiple matches there will now be an error (previously we would have used the first encoder as default vehicle).

I think it might be useful to merge these changes before in #1859 we:

1) Actually expose the new `profile` parameter via the web api. We probably also want to adjust the integration tests then and only keep a few that test the parameter conversion (profile selection). The good thing with this PR is that we can check if the conversion works before changing the tests etc.

2) Implement the merging rules between profile parameters and hints (e.g. take distance factor for short_fastest weighting from profile, but overwrite if given in request hints and not CH etc.)

Current todos for this PR:

* [x] adjust `config-example.yml`
* [x] add integration tests for edge_based/turn_costs parameter (and the corresponding conversion)/what about turn_cost=true/false cross querying for LM?
* [x] merge profile and request hints
 


Patch:
diff --git a/api/src/main/java/com/graphhopper/GHRequest.java b/api/src/main/java/com/graphhopper/GHRequest.java
index d57c627f7..1e228d0ea 100644
--- a/api/src/main/java/com/graphhopper/GHRequest.java
+++ b/api/src/main/java/com/graphhopper/GHRequest.java
@@ -34,6 +34,9 @@ import java.util.Locale;
  */
 public class GHRequest {
     private List<GHPoint> points;
+    // todo #1934: keep this here or put it into hints, and even more important: remove vehicle+weighting from
+    // hints?
+    private String profile = "";
     private final HintsMap hints = new HintsMap();
     // List of favored start (1st element) and arrival heading (all other).
     // Headings are north based azimuth (clockwise) in (0, 360) or NaN for equal preference
@@ -223,6 +226,15 @@ public class GHRequest {
         return setLocale(Helper.getLocale(localeStr));
     }
 
+    public String getProfile() {
+        return profile;
+    }
+
+    public GHRequest setProfile(String profile) {
+        this.profile = profile;
+        return this;
+    }
+
     public String getWeighting() {
         return hints.getWeighting();
     }
diff --git a/config-example.yml b/config-example.yml
index 10eac17c2..7483c30e6 100644
--- a/config-example.yml
+++ b/config-example.yml
@@ -22,7 +22,8 @@ graphhopper:
 
   ##### Routing Profiles ####
 
-  # Routing can be done for the following list of profiles. The fields of each profile are as follows:
+  # Routing can be done for the following list of profiles. Note that it is required to specify all the profiles you
+  # would like to use here. The fields of each profile are as follows:
   # - name (required): a unique string identifier for the profile
   # - vehicle (required): refers to the `graph.flag_encoders` used for this profile
   # - weighting (required): the weighting used for this profile, e.g. fastest,shortest or short_fastest
diff --git a/core/files/changelog.txt b/core/files/changelog.txt
index a692dbea3..ecddb3d82 100644
--- a/core/files/changelog.txt
+++ b/core/files/changelog.txt
@@ -1,4 +1,7 @@
 1.0
+    removed vehicle,weighting and edge_based from GraphHopper class, replaced with new profile parameter, #1958
+    all routing profiles have to be configured when setting up GraphHopper, #1958
+    there no longer is a default vehicle, not setting the vehicle now only works if there is exactly one profile that matches the other parameters. anyway you should use the new profile rather than the vehicle parameter.
     removed IPFilter. Use a firewall instead.
     PMap refactored. It is recommended to use putObject(String, Object) instead of put, #1956
     removed UnsafeDataAccess as not maintained, see #1620
diff --git a/core/src/main/java/com/graphhopper/GraphHopper.java b/core/src/main/java/com/graphhopper/GraphHopper.java
index 5b0eabc3e..864fcc8db 100644
--- a/core/src/main/java/com/graphhopper/GraphHopper.java
+++ b/core/src/main/java/com/graphhopper/GraphHopper.java
@@ -24,7 +24,10 @@ import com.graphhopper.json.geo.JsonFeature;
 import com.graphhopper.reader.DataReader;
 import com.graphhopper.reader.dem.*;
 import com.graphhopper.reader.osm.conditional.DateRangeParser;
-import com.graphhopper.routing.*;
+import com.graphhopper.routing.AlgorithmOptions;
+import com.graphhopper.routing.Path;
+import com.graphhopper.routing.RoutingAlgorithmFactory;
+import com.graphhopper.routing.RoutingAlgorithmFactorySimple;
 import com.graphhopper.routing.ch.CHPreparationHandler;
 import com.graphhopper.routing.ch.CHRoutingAlgorithmFactory;
 import com.graphhopper.routing.lm.LMPreparationHandler;
@@ -102,8 +105,6 @@ public class GraphHopper implements GraphHopperAPI {
     private boolean smoothElevation = false;
     // for routing
     private final RoutingConfig routingConfig = new RoutingConfig();
-    private ProfileResolver profileResolver = new ProfileResolver();
-
     // for index
     private LocationIndex locationIndex;
     private int preciseIndexResolution = 300;
@@ -140,13 +141,6 @@ public class GraphHopper implements GraphHopperAPI {
         return this;
     }
 
-    FlagEncoder getDefaultVehicle() {
-        if (encodingManager == null)
-            throw new IllegalStateException("No encoding manager specified or loaded");
-
-        return profileResolver.getDefaultVehicle(encodingManager);
-    }
-
     public EncodingManager getEncodingManager() {
         return encodingManager;
     }
@@ -491,15 +485,6 @@ public class GraphHopper implements GraphHopperAPI {
         return this;
     }
 
-    public ProfileResolver getProfileResolver() {
-        return this.profileResolver;
-    }
-
-    public GraphHopper setProfileResolver(ProfileResolver profileResolver) {
-        this.profileResolver = profileResolver;
-        return this;
-    }
-
     /**
      * Reads the configuration from a {@link GraphHopperConfig} object which can be manually filled, or more typically
      * is read from `config.yml`.
@@ -824,6 +809,11 @@ public class GraphHopper implements GraphHopperAPI {
     }
 
     private void checkProfilesConsistency() {
+        // todo: strictly speaking no profiles are needed, e.g. when we only use the location index, but this is rather
+        // the exception. we can move this check closer to the code that actually requires profiles after #1901
+        if (profilesByName.isEmpty()) {
+            throw new IllegalArgumentException("No routing profiles have been specified, you need to configure at least one");
+        }
         for (ProfileConfig profile : profilesByName.values()) {
             if (!encodingManager.hasEncoder(profile.getVehicle())) {
                 throw new IllegalArgumentException("Unknown vehicle '" + profile.getVehicle() + "' in profile: " + profile + ". Make sure all vehicles used in 'profiles' exist in 'graph.flag_encoders'");
@@ -864,13 +854,6 @@ public class GraphHopper implements GraphHopperAPI {
         }
     }
 
-    public ProfileConfig resolveProfile(HintsMap hints) {
-        if (encodingManager == null)
-            throw new IllegalStateException("No encoding manager specified or loaded");
-
-        return profileResolver.resolveProfile(encodingManager, chPreparationHandler.getCHProfiles(), lmPreparationHandler.getLMProfiles(), hints);
-    }
-
     public RoutingAlgorithmFactory getAlgorithmFactory(String profile, boolean disableCH, boolean disableLM) {
         if (chPreparationHandler.isEnabled() && disableCH && !chPreparationHandler.isDisablingAllowed()) {
             throw new IllegalArgumentException("Disabling CH is not allowed on the server side");
@@ -1030,7 +1013,18 @@ public class GraphHopper implements GraphHopperAPI {
         Lock readLock = readWriteLock.readLock();
         readLock.lock();
         try {
-            HintsMap hints = request.getHints();
+            if (!request.getVehicle().isEmpty())
+                throw new IllegalArgumentException("GHRequest may no longer contain a vehicle, use the profile parameter instead, see #1958");
+            if (!request.getWeighting().isEmpty())
+                throw new IllegalArgumentException("GHRequest may no longer contain a weighting, use the profile parameter instead, see #1958");
+            if (request.getHints().has(Routing.TURN_COSTS))
+                throw new IllegalArgumentException("GHRequest may no longer contain the turn_costs=true/false parameter, use the profile parameter instead, see #1958");
+            if (request.getHints().has(Routing.EDGE_BASED))
+                throw new IllegalArgumentException("GHRequest may no longer contain the edge_based=true/false parameter, use the profile parameter instead, see #1958");
+
+            // todo later: do not allow things like short_fastest.distance_factor or u_turn_costs unless CH is disabled and only under certain conditions for LM
+
+            PMap hints = request.getHints();
             boolean disableCH = hints.getBool(CH.DISABLE, false);
             if (chPreparationHandler.isEnabled() && !chPreparationHandler.isDisablingAllowed() && disableCH)
                 throw new IllegalArgumentException("Disabling CH not allowed on the server-side");
@@ -1056,10 +1050,17 @@ public class GraphHopper implements GraphHopperAPI {
             // For example see #734
             checkIfPointsAreInBounds(points);
 
-            ProfileConfig profile = resolveProfile(hints);
+            if (Helper.isEmpty(request.getProfile())) {
+                throw new IllegalArgumentException("You need to specify a profile to perform a routing request, see #1958");
+            }
+            ProfileConfig profile = profilesByName.get(request.getProfile());
+            if (profile == null) {
+                throw new IllegalArgumentException("The requested profile '" + request.getProfile() + "' does not exist");
+            }
             if (!profile.isTurnCosts() && !request.getCurbsides().isEmpty())
                 throw new IllegalArgumentException("To make use of the " + CURBSIDE + " parameter you need to use a profile that supports turn costs");
 
+            // todo later: should we be able to control this using the edge_based parameter?
             TraversalMode tMode = profile.isTurnCosts() ? TraversalMode.EDGE_BASED : TraversalMode.NODE_BASED;
 
             RoutingAlgorithmFactory algorithmFactory = getAlgorithmFactory(profile.getName(), disableCH, disableLM);
@@ -1350,13 +1351,22 @@ public class GraphHopper implements GraphHopperAPI {
             this.ghStorage = ghStorage;
         }
 
-        public Weighting createWeighting(ProfileConfig profile, PMap hints) {
+        public Weighting createWeighting(ProfileConfig profile, PMap requestHints) {
+            // Merge profile hints with request hints, the request hints take precedence.
+            // Note that so far we do not check if overwriting the profile hints actually works with the preparation
+            // for LM/CH. Later we should also limit the number of parameters that can be used to modify the profile.
+            // todo: since we are not dealing with block_area here yet we cannot really apply any merging rules
+            // for it, see discussion here: https://github.com/graphhopper/graphhopper/pull/1958#discussion_r395462901
+            PMap hints = new PMap();
+            hints.putAll(profile.getHints());
+            hints.putAll(requestHints);
+
             FlagEncoder encoder = encodingManager.getEncoder(profile.getVehicle());
             TurnCostProvider turnCostProvider;
             if (profile.isTurnCosts() && !hints.getBool("__disable_turn_costs_for_lm_preparation", false)) {
                 if (!encoder.supportsTurnCosts())
                     throw new IllegalArgumentException("Encoder " + encoder + " does not support turn costs");
-                int uTurnCosts = profile.getHints().getInt(Routing.U_TURN_COSTS, INFINITE_U_TURN_COSTS);
+                int uTurnCosts = hints.getInt(Routing.U_TURN_COSTS, INFINITE_U_TURN_COSTS);
                 turnCostProvider = new DefaultTurnCostProvider(encoder, ghStorage.getTurnCostStorage(), uTurnCosts);
             } else {
                 turnCostProvider = NO_TURN_COST_PROVIDER;
diff --git a/core/src/main/java/com/graphhopper/routing/ProfileResolver.java b/core/src/main/java/com/graphhopper/routing/ProfileResolver.java
index f30922a3a..3bf710b09 100644
--- a/core/src/main/java/com/graphhopper/routing/ProfileResolver.java
+++ b/core/src/main/java/com/graphhopper/routing/ProfileResolver.java
@@ -18,124 +18,134 @@
 
 package com.graphhopper.routing;
 
+import com.graphhopper.config.CHProfileConfig;
+import com.graphhopper.config.LMProfileConfig;
 import com.graphhopper.config.ProfileConfig;
-import com.graphhopper.routing.lm.LMProfile;
 import com.graphhopper.routing.util.EncodingManager;
-import com.graphhopper.routing.util.FlagEncoder;
 import com.graphhopper.routing.util.HintsMap;
-import com.graphhopper.storage.CHProfile;
+import com.graphhopper.util.PMap;
 import com.graphhopper.util.Parameters;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import static com.graphhopper.routing.weighting.Weighting.INFINITE_U_TURN_COSTS;
 
+/**
+ * Before the `profile` parameter was introduced in #1958 the cost-function used for route calculations could be
+ * specified by setting the vehicle and weighting parameters as well as the turn_costs/edge_based flag. This class does
+ * the conversion between these legacy parameters and the corresponding profile. To resolve a profile we consider both
+ * the request parameters as well as the available LM/CH preparations.
+ * Note that this class is meant to be only used for the top-most web layer, while the GH engine should only deal with
+ * the profile parameter.
+ */
 public class ProfileResolver {
+    private final EncodingManager encodingManager;
+    private final List<ProfileConfig> profiles;
+    private final List<ProfileConfig> chProfiles;
+    private final List<ProfileConfig> lmProfiles;
 
-    public ProfileConfig resolveProfile(EncodingManager encodingManager, List<CHProfile> chProfiles, List<LMProfile> lmProfiles, HintsMap hints) {
-        // default handling
-        String vehicle = hints.getVehicle();
-        if (vehicle.isEmpty()) {
-            vehicle = getDefaultVehicle(encodingManager).toString();
+    public ProfileResolver(EncodingManager encodingManager, List<ProfileConfig> profiles, List<CHProfileConfig> chProfiles, List<LMProfileConfig> lmProfiles) {
+        this.encodingManager = encodingManager;
+        this.profiles = profiles;
+        Map<String, ProfileConfig> profilesByName = new HashMap<>(profiles.size());
+        for (ProfileConfig p : profiles) {
+            profilesByName.put(p.getName(), p);
+        }
+        if (profilesByName.size() != profiles.size()) {
+            throw new IllegalStateException("Profiles must have distinct names");
+        }
+        this.chProfiles = new ArrayList<>();
+        for (CHProfileConfig p : chProfiles) {
+            ProfileConfig profile = profilesByName.get(p.getProfile());
+            if (profile == null) {
+                throw new IllegalStateException("There is no profile for CH preparation '" + p.getProfile() + "'");
+            }
+            this.chProfiles.add(profile);
         }
-        String weighting = hints.getWeighting();
-        if (weighting.isEmpty()) {
-            weighting = "fastest";
+        this.lmProfiles = new ArrayList<>();
+        for (LMProfileConfig p : lmProfiles) {
+            ProfileConfig profile = profilesByName.get(p.getProfile());
+            if (profile == null) {
+                throw new IllegalStateException("There is no profile for LM preparation '" + p.getProfile() + "'");
+            }
+            this.lmProfiles.add(profile);
         }
-        if (!encodingManager.hasEncoder(vehicle))
-            throw new IllegalArgumentException("Vehicle not supported: " + vehicle + ". Supported are: " + encodingManager.toString());
-
-        FlagEncoder encoder = encodingManager.getEncoder(vehicle);
-        // we use turn costs if the encoder supports it *unless* the edge_based parameter is set explicitly
-        boolean turnCosts = encoder.supportsTurnCosts();
-        if (hints.has(Parameters.Routing.EDGE_BASED))
-            turnCosts = hints.getBool(Parameters.Routing.EDGE_BASED, false);
-        if (turnCosts && !encoder.supportsTurnCosts())
-            throw new IllegalArgumentException("You need to set up a turn cost storage to make use of edge_based=true, e.g. use car|turn_costs=true");
-
-        // we make sure that 1) the hints are not modified and 2) the default vehicle is set in case it was missing
-        String profileName = resolveProfileName(chProfiles, lmProfiles, new HintsMap(hints).setVehicle(vehicle));
-
-        ProfileConfig profile = new ProfileConfig(profileName)
-                .setVehicle(vehicle)
-                .setWeighting(weighting)
-                .setTurnCosts(turnCosts);
-        profile.getHints().putAll(hints);
-        return profile;
     }
 
-    private String resolveProfileName(List<CHProfile> chProfiles, List<LMProfile> lmProfiles, HintsMap hints) {
+    public ProfileConfig resolveProfile(HintsMap hints) {
         boolean disableCH = hints.getBool(Parameters.CH.DISABLE, false);
         boolean disableLM = hints.getBool(Parameters.Landmark.DISABLE, false);
 
-        String profileName;
+        String vehicle = hints.getVehicle();
+        if (!vehicle.isEmpty() && !encodingManager.hasEncoder(hints.getVehicle()))
+            throw new IllegalArgumentException("Vehicle not supported: `" + vehicle + "`. Supported are: `" + encodingManager.toString() +
+                    "`\nYou should consider using the profile parameter instead of specifying a vehicle, see #1958");
+
+        // we select the profile based on the given request hints and the available profiles
         if (!chProfiles.isEmpty() && !disableCH) {
-            profileName = selectCHProfile(chProfiles, hints).getName();
+            return selectProfileCH(hints);
         } else if (!lmProfiles.isEmpty() && !disableLM) {
-            profileName = selectLMProfile(lmProfiles, hints).getName();
+            return selectProfileLM(hints);
         } else {
-            // todonow: here we will instead select one of the existing profiles
-            profileName = "unprepared_profile";
+            return selectProfileUnprepared(hints);
         }
-        return profileName;
     }
 
     /**
-     * @param chProfiles the CH profiles to choose from
-     * @param hintsMap   a map used to describe the CH profile that shall be selected
-     * @throws IllegalArgumentException if no CH profile could be selected for the given parameters
+     * @param hintsMap a map used to describe the profile that shall be selected
+     * @throws IllegalArgumentException if no profile supporting CH could be selected for the given parameters
      */
-    // todo: make private and/or make sure default vehicle is used
-    public CHProfile selectCHProfile(List<CHProfile> chProfiles, HintsMap hintsMap) {
-        int numMatchingEdgeBased = 0;
-        List<CHProfile> matchingProfiles = new ArrayList<>();
-        for (CHProfile p : chProfiles) {
+    public ProfileConfig selectProfileCH(HintsMap hintsMap) {
+        List<ProfileConfig> matchingProfiles = new ArrayList<>();
+        for (ProfileConfig p : chProfiles) {
             if (!chProfileMatchesHints(p, hintsMap))
                 continue;
             matchingProfiles.add(p);
-            if (p.isEdgeBased()) {
-                numMatchingEdgeBased++;
-            }
         }
 
         Boolean edgeBased = getEdgeBased(hintsMap);
         Integer uTurnCosts = getUTurnCosts(hintsMap);
         if (matchingProfiles.isEmpty()) {
-            throw new IllegalArgumentException("Cannot find matching CH profile for your request. Please check your parameters." +
+            throw new IllegalArgumentException("Cannot find matching profile that supports CH for your request. Please check your parameters." +
                     "\nYou can try disabling CH using " + Parameters.CH.DISABLE + "=true" +
-                    "\nrequested:  " + getCHRequestAsString(hintsMap, edgeBased, uTurnCosts) + "\navailable: " + chProfiles);
+                    "\nrequested:  " + getCHRequestAsString(hintsMap, edgeBased, uTurnCosts) + "\navailable: " + chProfilesAsString(chProfiles));
         } else if (matchingProfiles.size() == 1) {
             return matchingProfiles.get(0);
         } else {
-            // special case: prefer edge-based over node-based if these are the only two options
-            CHProfile match1 = matchingProfiles.get(0);
-            CHProfile match2 = matchingProfiles.get(1);
+            // special case: prefer profile with turn costs over one without turn costs if both are available and there
+            // aren't any other options
+            ProfileConfig match1 = matchingProfiles.get(0);
+            ProfileConfig match2 = matchingProfiles.get(1);
             if (edgeBased == null && matchingProfiles.size() == 2 &&
-                    match1.getWeighting().getName().equals(match2.getWeighting().getName()) &&
-                    match1.getWeighting().getFlagEncoder().toString().equals(match2.getWeighting().getFlagEncoder().toString()) &&
-                    match1.isEdgeBased() != match2.isEdgeBased()) {
-                return match1.isEdgeBased() ? match1 : match2;
+                    match1.getWeighting().equals(match2.getWeighting()) &&
+                    match1.getVehicle().equals(match2.getVehicle()) &&
+                    match1.isTurnCosts() != match2.isTurnCosts()) {
+                return match1.isTurnCosts() ? match1 : match2;
             }
-            // special case: error if multiple edge-based matches. to differentiate between these it will be required
-            // to explicitly set the profile parameter.
-            if (numMatchingEdgeBased > 1 && numMatchingEdgeBased == matchingProfiles.size()) {
-                throw new IllegalArgumentException("There are multiple edge-based CH profiles matching your request. You need to" +
-                        " specify the profile you want to use explicitly, see here: https://github.com/graphhopper/graphhopper/pull/1934.");
-            } else {
-                throw new IllegalArgumentException("There are multiple CH profiles matching your request. Use the `weighting`,`vehicle`,`edge_based` and/or `u_turn_costs` parameters to be more specific." +
-                        "\nYou can also try disabling CH altogether using " + Parameters.CH.DISABLE + "=true" +
-                        "\nrequested:  " + getCHRequestAsString(hintsMap, edgeBased, uTurnCosts) + "\nmatched:   " + matchingProfiles + "\navailable: " + chProfiles);
+            throw new IllegalArgumentException("There are multiple CH profiles matching your request. Use the `weighting`," +
+                    "`vehicle`,`turn_costs` and/or `u_turn_costs` parameters to be more specific or better use the `profile` parameter to explicitly choose a profile." +
+                    "\nYou can also try disabling CH altogether using " + Parameters.CH.DISABLE + "=true" +
+                    "\nrequested:  " + getCHRequestAsString(hintsMap, edgeBased, uTurnCosts) + "\nmatched:   " + chProfilesAsString(matchingProfiles) + "\navailable: " + chProfilesAsString(chProfiles));
 
-            }
         }
     }
 
-    // todo: make private and/or make sure default vehicle is used
-    public LMProfile selectLMProfile(List<LMProfile> lmProfiles, HintsMap hintsMap) {
-        List<LMProfile> matchingProfiles = new ArrayList<>();
-        for (LMProfile p : lmProfiles) {
-            if (!lmProfileMatchesHints(p, hintsMap))
+    protected boolean chProfileMatchesHints(ProfileConfig p, HintsMap hintsMap) {
+        Boolean edgeBased = getEdgeBased(hintsMap);
+        Integer uTurnCosts = getUTurnCosts(hintsMap);
+        return (edgeBased == null || p.isTurnCosts() == edgeBased) &&
+                (uTurnCosts == null || uTurnCosts.equals(getUTurnCosts(p.getHints()))) &&
+                (hintsMap.getWeighting().isEmpty() || p.getWeighting().equals(hintsMap.getWeighting())) &&
+                (hintsMap.getVehicle().isEmpty() || p.getVehicle().equals(hintsMap.getVehicle()));
+    }
+
+    public ProfileConfig selectProfileLM(HintsMap hintsMap) {
+        List<ProfileConfig> matchingProfiles = new ArrayList<>();
+        for (ProfileConfig p : lmProfiles) {
+            if (!profileMatchesHints(p, hintsMap))
                 continue;
             matchingProfiles.add(p);
         }
@@ -147,43 +157,72 @@ public class ProfileResolver {
         if (matchingProfiles.isEmpty()) {
             throw new IllegalArgumentException("Cannot find matching LM profile for your request. Please check your parameters." +
                     "\nYou can try disabling LM by setting " + Parameters.Landmark.DISABLE + "=true" +
-                    "\nrequested: " + getLMRequestAsString(hintsMap) + "\navailable: " + lmProfilesAsStrings(lmProfiles));
+                    "\nrequested:  " + getRequestAsString(hintsMap) + "\navailable: " + profilesAsString(lmProfiles));
         } else if (matchingProfiles.size() == 1) {
             return matchingProfiles.get(0);
         } else {
-            throw new IllegalArgumentException("There are multiple LM profiles matching your request. Use the `weighting` and `vehicle` parameters to be more specific." +
-                    "\nYou can also try disabling LM altogether using " + Parameters.CH.DISABLE + "=true" +
-                    "\nrequested:  " + getLMRequestAsString(hintsMap) + "\nmatched:   " + lmProfilesAsStrings(matchingProfiles) + "\navailable: " + lmProfilesAsStrings(lmProfiles));
+            // special case: prefer profile with turn costs over one without turn costs if both are available and there
+            // aren't any other options
+            ProfileConfig match1 = matchingProfiles.get(0);
+            ProfileConfig match2 = matchingProfiles.get(1);
+            Boolean edgeBased = getEdgeBased(hintsMap);
+            if (edgeBased == null && matchingProfiles.size() == 2 &&
+                    match1.getWeighting().equals(match2.getWeighting()) &&
+                    match1.getVehicle().equals(match2.getVehicle()) &&
+                    match1.isTurnCosts() != match2.isTurnCosts()) {
+                return match1.isTurnCosts() ? match1 : match2;
+            }
+            throw new IllegalArgumentException("There are multiple LM profiles matching your request. Use the `weighting`," +
+                    " `vehicle` and `turn_costs` parameters to be more specific or better use the `profile` parameter to explicitly choose a profile." +
+                    "\nYou can also try disabling LM altogether using " + Parameters.Landmark.DISABLE + "=true" +
+                    "\nrequested:  " + getRequestAsString(hintsMap) + "\nmatched:   " + profilesAsString(matchingProfiles) + "\navailable: " + profilesAsString(lmProfiles));
         }
     }
 
-    protected boolean chProfileMatchesHints(CHProfile p, HintsMap hintsMap) {
-        Boolean edgeBased = getEdgeBased(hintsMap);
-        Integer uTurnCosts = getUTurnCosts(hintsMap);
-        return (edgeBased == null || p.isEdgeBased() == edgeBased) &&
-                // u-turn costs cannot be used to select one of multiple edge-based CH profiles,
-                // but when they are set only edge-based profiles can match
-                (uTurnCosts == null || p.isEdgeBased()) &&
-                (hintsMap.getWeighting().isEmpty() || p.getWeighting().getName().equals(hintsMap.getWeighting())) &&
-                (hintsMap.getVehicle().isEmpty() || p.getWeighting().getFlagEncoder().toString().equals(hintsMap.getVehicle()));
-    }
-
-    protected boolean lmProfileMatchesHints(LMProfile p, HintsMap hintsMap) {
-        return (hintsMap.getWeighting().isEmpty() || p.getWeighting().getName().equals(hintsMap.getWeighting())) &&
-                (hintsMap.getVehicle().isEmpty() || p.getWeighting().getFlagEncoder().toString().equals(hintsMap.getVehicle()));
+    private ProfileConfig selectProfileUnprepared(HintsMap hints) {
+        List<ProfileConfig> matchingProfiles = new ArrayList<>();
+        for (ProfileConfig p : profiles) {
+            if (!profileMatchesHints(p, hints))
+                continue;
+            matchingProfiles.add(p);
+        }
+        if (matchingProfiles.isEmpty()) {
+            throw new IllegalArgumentException("Cannot find matching profile for your request. Please check your parameters." +
+                    "\nrequested: " + getRequestAsString(hints) + "\navailable: " + profilesAsString(profiles));
+        } else if (matchingProfiles.size() == 1) {
+            return matchingProfiles.get(0);
+        } else {
+            // special case: prefer profile with turn costs over one without turn costs if both are available and there
+            // aren't any other options
+            ProfileConfig match1 = matchingProfiles.get(0);
+            ProfileConfig match2 = matchingProfiles.get(1);
+            Boolean edgeBased = getEdgeBased(hints);
+            if (edgeBased == null && matchingProfiles.size() == 2 &&
+                    match1.getWeighting().equals(match2.getWeighting()) &&
+                    match1.getVehicle().equals(match2.getVehicle()) &&
+                    match1.isTurnCosts() != match2.isTurnCosts()) {
+                return match1.isTurnCosts() ? match1 : match2;
+            }
+            throw new IllegalArgumentException("There are multiple profiles matching your request. Use the `weighting`," +
+                    " `vehicle and `turn_costs` parameters to be more specific or better use the `profile` parameter to explicitly choose a profile." +
+                    "\nrequested:  " + getRequestAsString(hints) + "\nmatched:   " + profilesAsString(matchingProfiles) + "\navailable: " + profilesAsString(profiles));
+        }
     }
 
-    /**
-     * @return the first flag encoder of the encoding manager
-     */
-    public FlagEncoder getDefaultVehicle(EncodingManager encodingManager) {
-        return encodingManager.fetchEdgeEncoders().get(0);
+    private boolean profileMatchesHints(ProfileConfig p, HintsMap hints) {
+        Boolean edgeBased = getEdgeBased(hints);
+        return (edgeBased == null || p.isTurnCosts() == edgeBased) &&
+                (hints.getWeighting().isEmpty() || p.getWeighting().equals(hints.getWeighting())) &&
+                (hints.getVehicle().isEmpty() || p.getVehicle().equals(hints.getVehicle()));
     }
 
-    private String getLMRequestAsString(HintsMap map) {
+    private String getRequestAsString(HintsMap map) {
+        Boolean edgeBased = getEdgeBased(map);
         return (map.getWeighting().isEmpty() ? "*" : map.getWeighting()) +
                 "|" +
-                (map.getVehicle().isEmpty() ? "*" : map.getVehicle());
+                (map.getVehicle().isEmpty() ? "*" : map.getVehicle()) +
+                "|" +
+                "turn_costs=" + (edgeBased != null ? edgeBased : "*");
     }
 
     private String getCHRequestAsString(HintsMap hintsMap, Boolean edgeBased, Integer uTurnCosts) {
@@ -191,24 +230,34 @@ public class ProfileResolver {
                 "|" +
                 (hintsMap.getVehicle().isEmpty() ? "*" : hintsMap.getVehicle()) +
                 "|" +
-                "edge_based=" + (edgeBased != null ? edgeBased : "*") +
+                "turn_costs=" + (edgeBased != null ? edgeBased : "*") +
                 "|" +
                 "u_turn_costs=" + (uTurnCosts != null ? uTurnCosts : "*");
     }
 
-    private List<String> lmProfilesAsStrings(List<LMProfile> profiles) {
+    private List<String> profilesAsString(List<ProfileConfig> profiles) {
+        List<String> result = new ArrayList<>(profiles.size());
+        for (ProfileConfig p : profiles) {
+            result.add(p.getWeighting() + "|" + p.getVehicle() + "|turn_costs=" + p.isTurnCosts());
+        }
+        return result;
+    }
+
+    private List<String> chProfilesAsString(List<ProfileConfig> profiles) {
         List<String> result = new ArrayList<>(profiles.size());
-        for (LMProfile p : profiles) {
-            result.add(p.getWeighting().getName() + "|" + p.getWeighting().getFlagEncoder().toString());
+        for (ProfileConfig p : profiles) {
+            String str = p.getWeighting() + "|" + p.getVehicle() + "|turn_costs=" + p.isTurnCosts();
+            str += (p.isTurnCosts() ? "|u_turn_costs=" + p.getHints().getInt(Parameters.Routing.U_TURN_COSTS, INFINITE_U_TURN_COSTS) : "");
+            result.add(str);
         }
         return result;
     }
 
-    private Boolean getEdgeBased(HintsMap hintsMap) {
+    private Boolean getEdgeBased(PMap hintsMap) {
         return hintsMap.has(Parameters.Routing.EDGE_BASED) ? hintsMap.getBool(Parameters.Routing.EDGE_BASED, false) : null;
     }
 
-    private Integer getUTurnCosts(HintsMap hintsMap) {
+    private Integer getUTurnCosts(PMap hintsMap) {
         return hintsMap.has(Parameters.Routing.U_TURN_COSTS) ? hintsMap.getInt(Parameters.Routing.U_TURN_COSTS, INFINITE_U_TURN_COSTS) : null;
     }
 }
diff --git a/core/src/main/java/com/graphhopper/routing/lm/LandmarkStorage.java b/core/src/main/java/com/graphhopper/routing/lm/LandmarkStorage.java
index 76c77ddb1..14c08d297 100644
--- a/core/src/main/java/com/graphhopper/routing/lm/LandmarkStorage.java
+++ b/core/src/main/java/com/graphhopper/routing/lm/LandmarkStorage.java
@@ -817,7 +817,7 @@ public class LandmarkStorage implements Storable<LandmarkStorage> {
             if ((double) maxedout.get() / map.size() > 0.1) {
                 LOGGER.warn("landmark " + lmIdx + " (" + nodeAccess.getLatitude(lmNodeId) + "," + nodeAccess.getLongitude(lmNodeId) + "): " +
                         "too many weights were maxed out (" + maxedout.get() + "/" + map.size() + "). Use a bigger factor than " + lms.factor
-                        + ". For example use the following in the config.yml: weighting=" + weighting.getName() + "|maximum=" + finalMaxWeight.getValue() * 1.2);
+                        + ". For example use maximum_lm_weight: " + finalMaxWeight.getValue() * 1.2 + " in your LM profile definition");
             }
         }
     }
diff --git a/core/src/main/java/com/graphhopper/storage/GraphEdgeIdFinder.java b/core/src/main/java/com/graphhopper/storage/GraphEdgeIdFinder.java
index 21d179d59..8aa3731b2 100644
--- a/core/src/main/java/com/graphhopper/storage/GraphEdgeIdFinder.java
+++ b/core/src/main/java/com/graphhopper/storage/GraphEdgeIdFinder.java
@@ -20,7 +20,6 @@ package com.graphhopper.storage;
 import com.carrotsearch.hppc.cursors.IntCursor;
 import com.graphhopper.coll.GHIntHashSet;
 import com.graphhopper.routing.util.EdgeFilter;
-import com.graphhopper.routing.util.HintsMap;
 import com.graphhopper.storage.index.LocationIndex;
 import com.graphhopper.util.*;
 import com.graphhopper.util.shapes.Polygon;
@@ -86,7 +85,7 @@ public class GraphEdgeIdFinder {
     }
 
     public static GraphEdgeIdFinder.BlockArea createBlockArea(Graph graph, LocationIndex locationIndex,
-                                                              List<GHPoint> points, HintsMap hints, EdgeFilter edgeFilter) {
+                                                              List<GHPoint> points, PMap hints, EdgeFilter edgeFilter) {
         String blockAreaStr = hints.getString(Parameters.Routing.BLOCK_AREA, "");
         GraphEdgeIdFinder.BlockArea blockArea = new GraphEdgeIdFinder(graph, locationIndex).
                 parseBlockArea(blockAreaStr, edgeFilter, hints.getDouble(Parameters.Routing.BLOCK_AREA + ".edge_id_max_area", 1000 * 1000));
diff --git a/docs/web/api-doc.md b/docs/web/api-doc.md
index 47d2a1064..6c027a303 100644
--- a/docs/web/api-doc.md
+++ b/docs/web/api-doc.md
@@ -2,6 +2,7 @@
 
 In order to communicate with your or [our](http://graphhopper.com/#enterprise) hosted GraphHopper 
 server you need to understand how to use it. There is a separate [JavaScript](https://github.com/graphhopper/directions-api-js-client) and [Java](https://github.com/graphhopper/directions-api-java-client) client for this API or use the plain JSON response for your language.
+To find out how to use the hosted GraphHopper Directions API you should refer to the online documentation [here](https://docs.graphhopper.com/). This file describes the web API of the open source routing server.
 
 ### A simple example
 [http://localhost:8989/route?point=45.752193%2C-0.686646&point=46.229253%2C-0.32959](http://localhost:8989/route?point=45.752193%2C-0.686646&point=46.229253%2C-0.32959)
@@ -29,7 +30,7 @@ Parameter   | Default | Description
 point       | -       | Specify multiple points for which the route should be calculated. The order is important. Specify at least two points.
 locale      | en      | The locale of the resulting turn instructions. E.g. `pt_PT` for Portuguese or `de` for German
 instructions| true    | If instruction should be calculated and returned
-vehicle     | car     | The vehicle for which the route should be calculated. Other vehicles are foot, bike, motorcycle, hike, ...
+profile     | -       | The profile to be used for the route calculation.
 elevation   | false   | If `true` a third dimension - the elevation - is included in the polyline or in the GeoJson. IMPORTANT: If enabled you have to use a modified version of the decoding method or set points_encoded to `false`. See the points_encoded attribute for more details. Additionally a request can fail if the vehicle does not support elevation. See the features object for every vehicle.
 points_encoded   | true    | If `false` the coordinates in `point` and `snapped_waypoints` are returned as array using the order [lon,lat,elevation] for every point. If `true` the coordinates will be encoded as string leading to less bandwith usage. You'll need a special handling for the decoding of this string on the client-side. We provide open source code in [Java](https://github.com/graphhopper/graphhopper/blob/d70b63660ac5200b03c38ba3406b8f93976628a6/web/src/main/java/com/graphhopper/http/WebHelper.java#L43) and [JavaScript](https://github.com/graphhopper/graphhopper/blob/d70b63660ac5200b03c38ba3406b8f93976628a6/web/src/main/webapp/js/ghrequest.js#L139). It is especially important to use no 3rd party client if you set `elevation=true`!
 debug            | false   | If true, the output will be formated.
@@ -38,8 +39,6 @@ type             | json    | Specifies the resulting format of the route, for `j
 point_hint       | -       | Optional parameter. Specifies a hint for each `point` parameter to prefer a certain street for the closest location lookup. E.g. if there is an address or house with two or more neighboring streets you can control for which street the closest location is looked up.
 snap_prevention  | -       | Optional parameter to avoid snapping to a certain road class or road environment. Current supported values: `motorway`, `trunk`, `ferry`, `tunnel`, `bridge` and `ford`. Multiple values are specified like `snap_prevention=ferry&snap_prevention=motorway`
 details          | -       | Optional parameter. You can request additional details for the route: `average_speed`, `street_name`, `edge_id`, `road_class`, `road_environment`, `max_speed` and `time` (and see which other values are configured in `graph.encoded_values`).  Multiple values are specified like `details=average_speed&details=time`. The returned format for one detail segment is `[fromRef, toRef, value]`. The `ref` references the points of the response. Value can also be `null` if the property does not exist for one detail segment.
-turn_costs       | false   | Use `true` if you want to consider turn restrictions for bike and motor vehicles. Keep in mind that the response time is roughly 2 times slower.
-edge_based       | false   | Internal parameter to force edge-based algorithm.
 curbside         | any     | Optional parameter applicable to edge-based routing only. It specifies on which side a query point should be relative to the driver when she leaves/arrives at a start/target/via point. Possible values: right, left, any. Specify for every point parameter. See similar heading parameter.
 force_curbside   | false   | True if the curbside parameters should lead to an exception if they cannot be fulfilled.
 
@@ -60,7 +59,7 @@ and still benefit from a speed up.
 
 Parameter        | Default    | Description
 :----------------|:-----------|:-----------
-ch.disable       | `false`    | Set to `true` in order to use the hybrid mode for all weightings that are enabled
+ch.disable       | `false`    | Set to `true` in order to use the hybrid mode for the given profile, works only if the hybrid mode was enabled for this profile
 lm.active_landmarks| 4        | Not recommended to change this
 
 ### Flexible
@@ -71,7 +70,6 @@ empty list for `profiles_ch`.
 Parameter        | Default    | Description
 :----------------|:-----------|:-----------
 ch.disable       | `false`    | Use this parameter in combination with one or more parameters of this table
-weighting        | `fastest`  | Which kind of 'best' route calculation you need. Other option is `shortest` (e.g. for `vehicle=foot` or `bike`), `short_fastest` if time and distance is expensive (e.g. for `vehicle=truck`) and `curvature` (only for `vehicle=motorcycle`)
 algorithm        |`astarbi`   | The algorithm to calculate the route. Other options are `dijkstra`, `astar`, `astarbi`, `alternative_route` and `round_trip`
 block_area       | -          | Block road access via a point with the format `latitude,longitude` or an area defined by a circle `lat,lon,radius` or a rectangle `lat1,lon1,lat2,lon2`. Separate multiple areas with a semicolon `;`.
 heading          | NaN        | Favour a heading direction for a certain point. Specify either one heading for the start point or as many as there are points. In this case headings are associated by their order to the specific points. Headings are given as north based clockwise angle between 0 and 360 degree. This parameter also influences the tour generated with `algorithm=round_trip` and forces the initial direction.
@@ -245,7 +243,7 @@ All parameters are shown in the following table.
 
 Parameter                   | Default | Description
 :---------------------------|:--------|:-----------
-vehicle                     | car     | The vehicle for which the route should be calculated. Other vehicles are foot, bike, motorcycle, hike, ...
+profile                     |         | The profile to be used for the isochrone calculation.
 buckets                     | 1       | Number by which to divide the given `time_limit` to create `buckets` nested isochrones of time intervals `time_limit/buckets`, `time_limit/(buckets - 1)`, ... , `time_limit`. Applies analogously to `distance_limit`.
 reverse_flow                | false   | If false the flow goes from point to the polygon, if true the flow goes from the polygon inside to the point. Example usage for false: *How many potential customer can be reached within 30min travel time from your store* vs. true: *How many customers can reach your store within 30min travel time.* (optional, default to false)
 point                       |         | Specify the start coordinate (required). A string organized as `latitude,longitude`.
diff --git a/tools/src/main/java/com/graphhopper/tools/CHMeasurement.java b/tools/src/main/java/com/graphhopper/tools/CHMeasurement.java
index 2ff6d8861..d1081b5c4 100644
--- a/tools/src/main/java/com/graphhopper/tools/CHMeasurement.java
+++ b/tools/src/main/java/com/graphhopper/tools/CHMeasurement.java
@@ -320,11 +320,11 @@ public class CHMeasurement {
                 req.putHint(Parameters.Routing.EDGE_BASED, withTurnCosts);
                 req.putHint(Parameters.CH.DISABLE, lm);
                 req.putHint(Parameters.Landmark.DISABLE, !lm);
+                req.setProfile("car_profile");
                 if (!lm) {
                     req.setAlgorithm(algo);
                 } else {
                     req.putHint(Parameters.Landmark.ACTIVE_COUNT, 8);
-                    req.setWeighting("fastest"); // why do we need this for lm, but not ch ?
                 }
                 long start = nanoTime();
                 GHResponse route = graphHopper.route(req);
diff --git a/tools/src/main/java/com/graphhopper/tools/Measurement.java b/tools/src/main/java/com/graphhopper/tools/Measurement.java
index d469af4f4..108789be0 100644
--- a/tools/src/main/java/com/graphhopper/tools/Measurement.java
+++ b/tools/src/main/java/com/graphhopper/tools/Measurement.java
@@ -75,6 +75,7 @@ public class Measurement {
     private final Map<String, Object> properties = new TreeMap<>();
     private long seed;
     private int maxNode;
+    private String vehicle;
     private String weighting = "fastest";
 
     public static void main(String[] strs) throws IOException {
@@ -174,7 +175,7 @@ public class Measurement {
             throw new IllegalArgumentException("There has to be exactly one encoder for each measurement");
         }
         FlagEncoder encoder = encodingManager.fetchEdgeEncoders().get(0);
-        String vehicleStr = encoder.toString();
+        final String vehicleStr = encoder.toString();
 
         StopWatch sw = new StopWatch().start();
         try {
@@ -187,13 +188,13 @@ public class Measurement {
             printLocationIndexQuery(g, hopper.getLocationIndex(), count);
 
             if (runSlow) {
-                printTimeOfRouteQuery(hopper, new QuerySettings("routing", vehicleStr, count / 20, isCH, isLM).
+                printTimeOfRouteQuery(hopper, new QuerySettings("routing", count / 20, isCH, isLM).
                         withInstructions());
                 if (encoder.supportsTurnCosts())
-                    printTimeOfRouteQuery(hopper, new QuerySettings("routing_edge", vehicleStr, count / 20, isCH, isLM).
+                    printTimeOfRouteQuery(hopper, new QuerySettings("routing_edge", count / 20, isCH, isLM).
                             withInstructions().edgeBased());
                 if (!blockAreaStr.isEmpty())
-                    printTimeOfRouteQuery(hopper, new QuerySettings("routing_block_area", vehicleStr, count / 20, isCH, isLM).
+                    printTimeOfRouteQuery(hopper, new QuerySettings("routing_block_area", count / 20, isCH, isLM).
                             withInstructions().blockArea(blockAreaStr));
             }
 
@@ -201,50 +202,50 @@ public class Measurement {
                 System.gc();
                 isLM = true;
                 for (int activeLMCount : Arrays.asList(4, 8, 12, 16)) {
-                    printTimeOfRouteQuery(hopper, new QuerySettings("routingLM" + activeLMCount, vehicleStr, count / 4, isCH, isLM).
+                    printTimeOfRouteQuery(hopper, new QuerySettings("routingLM" + activeLMCount, count / 4, isCH, isLM).
                             withInstructions().activeLandmarks(activeLMCount));
                     if (encoder.supportsTurnCosts()) {
-                        printTimeOfRouteQuery(hopper, new QuerySettings("routingLM" + activeLMCount + "_edge", vehicleStr, count / 4, isCH, isLM).
+                        printTimeOfRouteQuery(hopper, new QuerySettings("routingLM" + activeLMCount + "_edge", count / 4, isCH, isLM).
                                 withInstructions().activeLandmarks(activeLMCount).edgeBased());
                     }
                 }
 
                 final int blockAreaActiveLMCount = 8;
                 if (!blockAreaStr.isEmpty())
-                    printTimeOfRouteQuery(hopper, new QuerySettings("routingLM" + blockAreaActiveLMCount + "_block_area", vehicleStr, count / 4, isCH, isLM).
+                    printTimeOfRouteQuery(hopper, new QuerySettings("routingLM" + blockAreaActiveLMCount + "_block_area", count / 4, isCH, isLM).
                             withInstructions().activeLandmarks(blockAreaActiveLMCount).blockArea(blockAreaStr));
-                // compareRouting(hopper, vehicleStr, count / 5);
+                // compareRouting(hopper, count / 5);
             }
 
             if (hopper.getCHPreparationHandler().isEnabled()) {
                 isCH = true;
                 isLM = false;
-//                compareCHWithAndWithoutSOD(hopper, vehicleStr, count/5);
+//                compareCHWithAndWithoutSOD(hopper, count/5);
                 System.gc();
                 if (!hopper.getCHPreparationHandler().getNodeBasedCHProfiles().isEmpty()) {
                     CHProfile chProfile = hopper.getCHPreparationHandler().getNodeBasedCHProfiles().get(0);
                     CHGraph lg = g.getCHGraph(chProfile);
                     fillAllowedEdges(lg.getAllEdges(), allowedEdges);
                     printMiscUnitPerfTests(lg, isCH, encoder, count * 100, allowedEdges);
-                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH", vehicleStr, count, isCH, isLM).
+                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH", count, isCH, isLM).
                             withInstructions().sod());
-                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_alt", vehicleStr, count / 10, isCH, isLM).
+                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_alt", count / 10, isCH, isLM).
                             withInstructions().sod().alternative());
-                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_with_hints", vehicleStr, count, isCH, isLM).
+                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_with_hints", count, isCH, isLM).
                             withInstructions().sod().withPointHints());
-                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_no_sod", vehicleStr, count, isCH, isLM).
+                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_no_sod", count, isCH, isLM).
                             withInstructions());
-                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_no_instr", vehicleStr, count, isCH, isLM).
+                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_no_instr", count, isCH, isLM).
                             sod());
-                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_full", vehicleStr, count, isCH, isLM).
+                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_full", count, isCH, isLM).
                             withInstructions().withPointHints().sod().simplify());
                 }
                 if (!hopper.getCHPreparationHandler().getEdgeBasedCHProfiles().isEmpty()) {
-                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_edge", vehicleStr, count, isCH, isLM).
+                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_edge", count, isCH, isLM).
                             edgeBased().withInstructions());
-                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_edge_no_instr", vehicleStr, count, isCH, isLM).
+                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_edge_no_instr", count, isCH, isLM).
                             edgeBased());
-                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_edge_full", vehicleStr, count, isCH, isLM).
+                    printTimeOfRouteQuery(hopper, new QuerySettings("routingCH_edge_full", count, isCH, isLM).
                             edgeBased().withInstructions().withPointHints().simplify());
                 }
             }
@@ -282,7 +283,7 @@ public class Measurement {
         if (tmpEncoders.size() != 1) {
             logger.warn("You configured multiple encoders, only the first one is used for the measurements");
         }
-        String vehicle = tmpEncoders.get(0).toString();
+        vehicle = tmpEncoders.get(0).toString();
         boolean turnCosts = tmpEncoders.get(0).supportsTurnCosts();
         weighting = args.getString("measurement.weighting", weighting);
         boolean useCHEdge = args.getBool("measurement.ch.edge", true);
@@ -301,23 +302,27 @@ public class Measurement {
         if (useCHEdge)
             chProfiles.add(new CHProfileConfig("profile_tc"));
         ghConfig.setCHProfiles(chProfiles);
+        List<LMProfileConfig> lmProfiles = new ArrayList<>();
         if (useLM) {
-            String lmProfile = turnCosts ? "profile_tc" : "profile_no_tc";
-            ghConfig.setLMProfiles(Collections.singletonList(new LMProfileConfig(lmProfile)));
+            // as currently we do not allow cross-querying LM with turn costs=true/false we have to add both
+            // profiles and this currently leads to two identical LM preparations
+            lmProfiles.add(new LMProfileConfig("profile_no_tc"));
+            if (turnCosts)
+                lmProfiles.add(new LMProfileConfig("profile_tc"));
         }
+        ghConfig.setLMProfiles(lmProfiles);
         return ghConfig;
     }
 
     private static class QuerySettings {
-        private final String prefix, vehicle;
+        private final String prefix;
         private final int count;
         final boolean ch, lm;
         int activeLandmarks = -1;
         boolean withInstructions, withPointHints, sod, edgeBased, simplify, alternative;
         String blockArea;
 
-        QuerySettings(String prefix, String vehicle, int count, boolean isCH, boolean isLM) {
-            this.vehicle = vehicle;
+        QuerySettings(String prefix, int count, boolean isCH, boolean isLM) {
             this.prefix = prefix;
             this.count = count;
             this.ch = isCH;
@@ -528,7 +533,7 @@ public class Measurement {
         print("spatialrulelookup", lookupPerfTest);
     }
 
-    private void compareRouting(final GraphHopper hopper, String vehicle, int count) {
+    private void compareRouting(final GraphHopper hopper, int count) {
         logger.info("Comparing " + count + " routes. Differences will be printed to stderr.");
         String algo = Algorithms.ASTAR_BI;
         final Random rand = new Random(seed);
@@ -544,8 +549,7 @@ public class Measurement {
             double toLat = na.getLatitude(to);
             double toLon = na.getLongitude(to);
             GHRequest req = new GHRequest(fromLat, fromLon, toLat, toLon).
-                    setWeighting(weighting).
-                    setVehicle(vehicle).
+                    setProfile("profile_no_tc").
                     setAlgorithm(algo);
 
             GHResponse lmRsp = hopper.route(req);
@@ -569,7 +573,7 @@ public class Measurement {
         }
     }
 
-    private void compareCHWithAndWithoutSOD(final GraphHopper hopper, String vehicle, int count) {
+    private void compareCHWithAndWithoutSOD(final GraphHopper hopper, int count) {
         logger.info("Comparing " + count + " routes for CH with and without stall on demand." +
                 " Differences will be printed to stderr.");
         final Random rand = new Random(seed);
@@ -585,13 +589,11 @@ public class Measurement {
             double toLat = na.getLatitude(to);
             double toLon = na.getLongitude(to);
             GHRequest sodReq = new GHRequest(fromLat, fromLon, toLat, toLon).
-                    setWeighting(weighting).
-                    setVehicle(vehicle).
+                    setProfile("profile_no_tc").
                     setAlgorithm(DIJKSTRA_BI);
 
             GHRequest noSodReq = new GHRequest(fromLat, fromLon, toLat, toLon).
-                    setWeighting(weighting).
-                    setVehicle(vehicle).
+                    setProfile("profile_no_tc").
                     setAlgorithm(DIJKSTRA_BI);
             noSodReq.putHint("stall_on_demand", false);
 
@@ -629,7 +631,7 @@ public class Measurement {
         final AtomicInteger failedCount = new AtomicInteger(0);
         final DistanceCalc distCalc = new DistanceCalcEarth();
 
-        final EdgeFilter edgeFilter = DefaultEdgeFilter.allEdges(hopper.getEncodingManager().getEncoder(querySettings.vehicle));
+        final EdgeFilter edgeFilter = DefaultEdgeFilter.allEdges(hopper.getEncodingManager().getEncoder(vehicle));
         final EdgeExplorer edgeExplorer = g.createEdgeExplorer(edgeFilter);
         final AtomicLong visitedNodesSum = new AtomicLong(0);
         final AtomicLong maxVisitedNodes = new AtomicLong(0);
@@ -644,9 +646,8 @@ public class Measurement {
             @Override
             public int doCalc(boolean warmup, int run) {
                 int from = -1, to = -1;
-                Double fromLat = null, fromLon = null, toLat = null, toLon = null;
+                double fromLat = 0, fromLon = 0, toLat = 0, toLon = 0;
                 GHRequest req = null;
-
                 for (int i = 0; i < 5; i++) {
                     from = rand.nextInt(maxNode);
                     to = rand.nextInt(maxNode);
@@ -654,10 +655,8 @@ public class Measurement {
                     fromLon = na.getLongitude(from);
                     toLat = na.getLatitude(to);
                     toLon = na.getLongitude(to);
-                    req = new GHRequest(fromLat, fromLon, toLat, toLon).
-                            setWeighting(weighting).
-                            setVehicle(querySettings.vehicle);
-
+                    req = new GHRequest(fromLat, fromLon, toLat, toLon);
+                    req.setProfile(querySettings.edgeBased ? "profile_tc" : "profile_no_tc");
                     if (querySettings.blockArea == null)
                         break;
 
@@ -672,9 +671,9 @@ public class Measurement {
                     }
                 }
 
-                req.getHints().putObject(CH.DISABLE, !querySettings.ch).
+                req.getHints().
+                        putObject(CH.DISABLE, !querySettings.ch).
                         putObject("stall_on_demand", querySettings.sod).
-                        putObject(Parameters.Routing.EDGE_BASED, querySettings.edgeBased).
                         putObject(Landmark.DISABLE, !querySettings.lm).
                         putObject(Landmark.ACTIVE_COUNT, querySettings.activeLandmarks).
                         putObject("instructions", querySettings.withInstructions);
diff --git a/web-bundle/src/main/java/com/graphhopper/http/GraphHopperBundle.java b/web-bundle/src/main/java/com/graphhopper/http/GraphHopperBundle.java
index e059c476f..48f2bb4cf 100644
--- a/web-bundle/src/main/java/com/graphhopper/http/GraphHopperBundle.java
+++ b/web-bundle/src/main/java/com/graphhopper/http/GraphHopperBundle.java
@@ -37,6 +37,7 @@ import com.graphhopper.reader.gtfs.GraphHopperGtfs;
 import com.graphhopper.reader.gtfs.GtfsStorage;
 import com.graphhopper.reader.gtfs.PtRouteResource;
 import com.graphhopper.resources.*;
+import com.graphhopper.routing.ProfileResolver;
 import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.storage.GraphHopperStorage;
 import com.graphhopper.storage.index.LocationIndex;
@@ -199,12 +200,15 @@ public class GraphHopperBundle implements ConfiguredBundle<GraphHopperBundleConf
 
         final GraphHopperManaged graphHopperManaged = new GraphHopperManaged(configuration.getGraphHopperConfiguration(), environment.getObjectMapper());
         environment.lifecycle().manage(graphHopperManaged);
+        final GraphHopper graphHopper = graphHopperManaged.getGraphHopper();
         environment.jersey().register(new AbstractBinder() {
             @Override
             protected void configure() {
                 bind(configuration.getGraphHopperConfiguration()).to(GraphHopperConfig.class);
-                bind(graphHopperManaged.getGraphHopper()).to(GraphHopper.class);
-                bind(graphHopperManaged.getGraphHopper()).to(GraphHopperAPI.class);
+                bind(graphHopper).to(GraphHopper.class);
+                bind(graphHopper).to(GraphHopperAPI.class);
+                bind(new ProfileResolver(graphHopper.getEncodingManager(), graphHopper.getProfiles(), graphHopper.getCHPreparationHandler().getCHProfileConfigs(), graphHopper.getLMPreparationHandler().getLMProfileConfigs()))
+                        .to(ProfileResolver.class);
 
                 bindFactory(HasElevation.class).to(Boolean.class).named("hasElevation");
                 bindFactory(LocationIndexFactory.class).to(LocationIndex.class);
@@ -234,6 +238,6 @@ public class GraphHopperBundle implements ConfiguredBundle<GraphHopperBundleConf
         environment.jersey().register(SPTResource.class);
         environment.jersey().register(I18NResource.class);
         environment.jersey().register(InfoResource.class);
-        environment.healthChecks().register("graphhopper", new GraphHopperHealthCheck(graphHopperManaged.getGraphHopper()));
+        environment.healthChecks().register("graphhopper", new GraphHopperHealthCheck(graphHopper));
     }
 }
diff --git a/web-bundle/src/main/java/com/graphhopper/resources/IsochroneResource.java b/web-bundle/src/main/java/com/graphhopper/resources/IsochroneResource.java
index 0aeabfaf4..92a980193 100644
--- a/web-bundle/src/main/java/com/graphhopper/resources/IsochroneResource.java
+++ b/web-bundle/src/main/java/com/graphhopper/resources/IsochroneResource.java
@@ -8,6 +8,7 @@ import com.graphhopper.http.WebHelper;
 import com.graphhopper.isochrone.algorithm.ContourBuilder;
 import com.graphhopper.isochrone.algorithm.Isochrone;
 import com.graphhopper.json.geo.JsonFeature;
+import com.graphhopper.routing.ProfileResolver;
 import com.graphhopper.routing.querygraph.QueryGraph;
 import com.graphhopper.routing.util.*;
 import com.graphhopper.routing.weighting.BlockAreaWeighting;
@@ -41,12 +42,14 @@ public class IsochroneResource {
     private static final Logger logger = LoggerFactory.getLogger(IsochroneResource.class);
 
     private final GraphHopper graphHopper;
+    private final ProfileResolver profileResolver;
     private final EncodingManager encodingManager;
     private final GeometryFactory geometryFactory = new GeometryFactory();
 
     @Inject
-    public IsochroneResource(GraphHopper graphHopper, EncodingManager encodingManager) {
+    public IsochroneResource(GraphHopper graphHopper, ProfileResolver profileResolver, EncodingManager encodingManager) {
         this.graphHopper = graphHopper;
+        this.profileResolver = profileResolver;
         this.encodingManager = encodingManager;
     }
 
@@ -76,7 +79,8 @@ public class IsochroneResource {
         RouteResource.initHints(hintsMap, uriInfo.getQueryParameters());
         hintsMap.putObject(Parameters.CH.DISABLE, true);
         hintsMap.putObject(Parameters.Landmark.DISABLE, true);
-        ProfileConfig profile = graphHopper.resolveProfile(hintsMap);
+        // todo: #1934, only try to resolve the profile if no profile is given!
+        ProfileConfig profile = profileResolver.resolveProfile(hintsMap);
         if (profile.isTurnCosts()) {
             throw new IllegalArgumentException("Isochrone calculation does not support turn costs yet");
         }
diff --git a/web-bundle/src/main/java/com/graphhopper/resources/RouteResource.java b/web-bundle/src/main/java/com/graphhopper/resources/RouteResource.java
index 6c0e213e9..0d3170ca7 100644
--- a/web-bundle/src/main/java/com/graphhopper/resources/RouteResource.java
+++ b/web-bundle/src/main/java/com/graphhopper/resources/RouteResource.java
@@ -21,7 +21,9 @@ import com.graphhopper.GHRequest;
 import com.graphhopper.GHResponse;
 import com.graphhopper.GraphHopperAPI;
 import com.graphhopper.MultiException;
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.WebHelper;
+import com.graphhopper.routing.ProfileResolver;
 import com.graphhopper.routing.util.HintsMap;
 import com.graphhopper.util.Constants;
 import com.graphhopper.util.Helper;
@@ -59,11 +61,13 @@ public class RouteResource {
     private static final Logger logger = LoggerFactory.getLogger(RouteResource.class);
 
     private final GraphHopperAPI graphHopper;
+    private final ProfileResolver profileResolver;
     private final Boolean hasElevation;
 
     @Inject
-    public RouteResource(GraphHopperAPI graphHopper, @Named("hasElevation") Boolean hasElevation) {
+    public RouteResource(GraphHopperAPI graphHopper, ProfileResolver profileResolver, @Named("hasElevation") Boolean hasElevation) {
         this.graphHopper = graphHopper;
+        this.profileResolver = profileResolver;
         this.hasElevation = hasElevation;
     }
 
@@ -130,8 +134,11 @@ public class RouteResource {
         initHints(request.getHints(), uriInfo.getQueryParameters());
         translateTurnCostsParamToEdgeBased(request, uriInfo.getQueryParameters());
         enableEdgeBasedIfThereAreCurbsides(curbsides, request);
-        request.setVehicle(vehicleStr).
-                setWeighting(weighting).
+        // todo: #1934, only try to resolve the profile if no profile is given!
+        ProfileConfig profile = profileResolver.resolveProfile(request.getHints());
+        removeLegacyParameters(request);
+
+        request.setProfile(profile.getName()).
                 setAlgorithm(algoStr).
                 setLocale(localeStr).
                 setPointHints(pointHints).
@@ -179,6 +186,10 @@ public class RouteResource {
             throw new IllegalArgumentException("Empty request");
 
         StopWatch sw = new StopWatch().start();
+        // todo: #1934, only try to resolve the profile if no profile is given!
+        ProfileConfig profile = profileResolver.resolveProfile(request.getHints());
+        request.setProfile(profile.getName());
+        removeLegacyParameters(request);
         GHResponse ghResponse = graphHopper.route(request);
 
         boolean instructions = request.getHints().getBool(INSTRUCTIONS, true);
@@ -240,6 +251,14 @@ public class RouteResource {
         }
     }
 
+    private void removeLegacyParameters(GHRequest request) {
+        // these parameters should only be used to resolve the profile, but should not be passed to GraphHopper
+        request.getHints().setWeighting("");
+        request.getHints().setVehicle("");
+        request.getHints().remove("edge_based");
+        request.getHints().remove("turn_costs");
+    }
+
     private static Response.ResponseBuilder gpxSuccessResponseBuilder(GHResponse ghRsp, String timeString, String
             trackName, boolean enableElevation, boolean withRoute, boolean withTrack, boolean withWayPoints, String version) {
         if (ghRsp.getAll().size() > 1) {
diff --git a/web-bundle/src/main/java/com/graphhopper/resources/SPTResource.java b/web-bundle/src/main/java/com/graphhopper/resources/SPTResource.java
index d31432129..6d3d71842 100644
--- a/web-bundle/src/main/java/com/graphhopper/resources/SPTResource.java
+++ b/web-bundle/src/main/java/com/graphhopper/resources/SPTResource.java
@@ -3,6 +3,7 @@ package com.graphhopper.resources;
 import com.graphhopper.GraphHopper;
 import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.isochrone.algorithm.Isochrone;
+import com.graphhopper.routing.ProfileResolver;
 import com.graphhopper.routing.profiles.*;
 import com.graphhopper.routing.querygraph.QueryGraph;
 import com.graphhopper.routing.util.*;
@@ -38,11 +39,13 @@ public class SPTResource {
     private static final Logger logger = LoggerFactory.getLogger(SPTResource.class);
 
     private final GraphHopper graphHopper;
+    private final ProfileResolver profileResolver;
     private final EncodingManager encodingManager;
 
     @Inject
-    public SPTResource(GraphHopper graphHopper, EncodingManager encodingManager) {
+    public SPTResource(GraphHopper graphHopper, ProfileResolver profileResolver, EncodingManager encodingManager) {
         this.graphHopper = graphHopper;
+        this.profileResolver = profileResolver;
         this.encodingManager = encodingManager;
     }
 
@@ -64,7 +67,8 @@ public class SPTResource {
         RouteResource.initHints(hintsMap, uriInfo.getQueryParameters());
         hintsMap.putObject(Parameters.CH.DISABLE, true);
         hintsMap.putObject(Parameters.Landmark.DISABLE, true);
-        ProfileConfig profile = graphHopper.resolveProfile(hintsMap);
+        // todo: #1934, only try to resolve the profile if no profile is given!
+        ProfileConfig profile = profileResolver.resolveProfile(hintsMap);
         if (profile.isTurnCosts()) {
             throw new IllegalArgumentException("SPT calculation does not support turn costs yet");
         }


Test patch:
diff --git a/client-hc/src/test/java/com/graphhopper/api/GraphHopperWebIT.java b/client-hc/src/test/java/com/graphhopper/api/GraphHopperWebIT.java
index cba4365b7..fb8f9a08b 100644
--- a/client-hc/src/test/java/com/graphhopper/api/GraphHopperWebIT.java
+++ b/client-hc/src/test/java/com/graphhopper/api/GraphHopperWebIT.java
@@ -285,7 +285,7 @@ public class GraphHopperWebIT {
         String res = gh.export(req);
         assertTrue(res.contains("<gpx"));
         assertTrue(res.contains("<rtept lat="));
-        assertTrue(!res.contains("<trk><name>GraphHopper Track</name><trkseg>"));
+        assertFalse(res.contains("<trk><name>GraphHopper Track</name><trkseg>"));
         assertTrue(res.endsWith("</gpx>"));
     }
 
diff --git a/core/src/main/java/com/graphhopper/routing/weighting/FastestWeighting.java b/core/src/main/java/com/graphhopper/routing/weighting/FastestWeighting.java
index 4c94ef41e..3b594a989 100644
--- a/core/src/main/java/com/graphhopper/routing/weighting/FastestWeighting.java
+++ b/core/src/main/java/com/graphhopper/routing/weighting/FastestWeighting.java
@@ -20,7 +20,6 @@ package com.graphhopper.routing.weighting;
 import com.graphhopper.routing.profiles.EnumEncodedValue;
 import com.graphhopper.routing.profiles.RoadAccess;
 import com.graphhopper.routing.util.FlagEncoder;
-import com.graphhopper.routing.util.HintsMap;
 import com.graphhopper.routing.util.spatialrules.TransportationMode;
 import com.graphhopper.util.EdgeIteratorState;
 import com.graphhopper.util.PMap;
@@ -49,11 +48,11 @@ public class FastestWeighting extends AbstractWeighting {
     private final double destinationPenalty, privatePenalty;
 
     public FastestWeighting(FlagEncoder encoder) {
-        this(encoder, new HintsMap(0));
+        this(encoder, new PMap(0));
     }
 
     public FastestWeighting(FlagEncoder encoder, TurnCostProvider turnCostProvider) {
-        this(encoder, new HintsMap(0), turnCostProvider);
+        this(encoder, new PMap(0), turnCostProvider);
     }
 
     public FastestWeighting(FlagEncoder encoder, PMap map) {
diff --git a/core/src/test/java/com/graphhopper/GraphHopperAPITest.java b/core/src/test/java/com/graphhopper/GraphHopperAPITest.java
index 9f58a80a0..e622bf12f 100644
--- a/core/src/test/java/com/graphhopper/GraphHopperAPITest.java
+++ b/core/src/test/java/com/graphhopper/GraphHopperAPITest.java
@@ -17,6 +17,7 @@
  */
 package com.graphhopper;
 
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.json.geo.JsonFeature;
 import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.storage.Graph;
@@ -57,6 +58,7 @@ public class GraphHopperAPITest {
 
     @Test
     public void testLoad() {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "fastest";
         GraphHopperStorage graph = new GraphBuilder(EncodingManager.create(vehicle)).create();
@@ -70,10 +72,11 @@ public class GraphHopperAPITest {
         graph.edge(4, 3, 40, true);
 
         GraphHopper instance = createGraphHopper(vehicle).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(false).
                 loadGraph(graph);
         // 3 -> 0
-        GHResponse rsp = instance.route(new GHRequest(42, 10.4, 42, 10).setVehicle(vehicle).setWeighting(weighting));
+        GHResponse rsp = instance.route(new GHRequest(42, 10.4, 42, 10).setProfile(profile));
         assertFalse(rsp.hasErrors());
         PathWrapper arsp = rsp.getBest();
         assertEquals(80, arsp.getDistance(), 1e-6);
@@ -89,15 +92,17 @@ public class GraphHopperAPITest {
 
     @Test
     public void testDisconnected179() {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "fastest";
         GraphHopperStorage graph = new GraphBuilder(EncodingManager.create(vehicle)).create();
         initGraph(graph);
 
         GraphHopper instance = createGraphHopper(vehicle).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(false).
                 loadGraph(graph);
-        GHResponse rsp = instance.route(new GHRequest(42, 10, 42, 10.4).setVehicle(vehicle).setWeighting(weighting));
+        GHResponse rsp = instance.route(new GHRequest(42, 10, 42, 10.4).setProfile(profile));
         assertTrue(rsp.hasErrors());
 
         try {
@@ -144,6 +149,7 @@ public class GraphHopperAPITest {
             }
         }
                 .setEncodingManager(encodingManager)
+                .setProfiles(new ProfileConfig(vehicle).setVehicle(vehicle).setWeighting("fastest"))
                 .setElevation(true);
         instance.load(loc);
         instance.flush();
@@ -158,6 +164,7 @@ public class GraphHopperAPITest {
             }
         }
                 .setEncodingManager(encodingManager)
+                .setProfiles(new ProfileConfig(vehicle).setVehicle(vehicle).setWeighting("fastest"))
                 .setElevation(true);
         instance.load(loc);
         instance.flush();
@@ -169,12 +176,14 @@ public class GraphHopperAPITest {
 
     @Test
     public void testNoLoad() {
+        String profile = "profile";
         String vehicle = "car";
         String weighting = "fastest";
         GraphHopper instance = createGraphHopper(vehicle).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setVehicle(weighting)).
                 setStoreOnFlush(false);
         try {
-            instance.route(new GHRequest(42, 10.4, 42, 10).setVehicle(vehicle).setWeighting(weighting));
+            instance.route(new GHRequest(42, 10.4, 42, 10).setProfile(profile));
             fail();
         } catch (Exception ex) {
             assertTrue(ex.getMessage(), ex.getMessage().startsWith("Do a successful call to load or importOrLoad before routing"));
@@ -182,7 +191,7 @@ public class GraphHopperAPITest {
 
         instance = createGraphHopper(vehicle);
         try {
-            instance.route(new GHRequest(42, 10.4, 42, 10).setVehicle(vehicle).setWeighting(weighting));
+            instance.route(new GHRequest(42, 10.4, 42, 10).setProfile(profile));
             fail();
         } catch (Exception ex) {
             assertTrue(ex.getMessage(), ex.getMessage().startsWith("Do a successful call to load or importOrLoad before routing"));
@@ -191,6 +200,7 @@ public class GraphHopperAPITest {
 
     @Test
     public void testConcurrentGraphChange() throws InterruptedException {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "fastest";
         EncodingManager encodingManager = EncodingManager.create(vehicle);
@@ -220,10 +230,11 @@ public class GraphHopperAPITest {
             }
         }
                 .setEncodingManager(encodingManager)
+                .setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting))
                 .setStoreOnFlush(false).
                         loadGraph(graph);
 
-        GHResponse rsp = graphHopper.route(new GHRequest(42, 10.4, 42, 10).setVehicle(vehicle).setWeighting(weighting));
+        GHResponse rsp = graphHopper.route(new GHRequest(42, 10.4, 42, 10).setProfile(profile));
         assertFalse(rsp.toString(), rsp.hasErrors());
         assertEquals(1800, rsp.getBest().getTime());
 
@@ -246,7 +257,7 @@ public class GraphHopperAPITest {
 
         latch.await();
         assertEquals(0, checkPointCounter.get());
-        rsp = graphHopper.route(new GHRequest(42, 10.4, 42, 10).setVehicle(vehicle).setWeighting(weighting));
+        rsp = graphHopper.route(new GHRequest(42, 10.4, 42, 10).setProfile(profile));
         assertFalse(rsp.toString(), rsp.hasErrors());
         assertEquals(8400, rsp.getBest().getTime());
 
@@ -258,6 +269,7 @@ public class GraphHopperAPITest {
 
     private GraphHopper createGraphHopper(String vehicle) {
         return new GraphHopper()
-                .setEncodingManager(EncodingManager.create(vehicle));
+                .setEncodingManager(EncodingManager.create(vehicle))
+                .setProfiles(new ProfileConfig(vehicle).setVehicle(vehicle).setWeighting("fastest"));
     }
 }
diff --git a/core/src/test/java/com/graphhopper/routing/ProfileResolverTest.java b/core/src/test/java/com/graphhopper/routing/ProfileResolverTest.java
new file mode 100644
index 000000000..f4c796260
--- /dev/null
+++ b/core/src/test/java/com/graphhopper/routing/ProfileResolverTest.java
@@ -0,0 +1,168 @@
+/*
+ *  Licensed to GraphHopper GmbH under one or more contributor
+ *  license agreements. See the NOTICE file distributed with this work for
+ *  additional information regarding copyright ownership.
+ *
+ *  GraphHopper GmbH licenses this file to you under the Apache License,
+ *  Version 2.0 (the "License"); you may not use this file except in
+ *  compliance with the License. You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package com.graphhopper.routing;
+
+import com.graphhopper.config.CHProfileConfig;
+import com.graphhopper.config.LMProfileConfig;
+import com.graphhopper.config.ProfileConfig;
+import com.graphhopper.routing.ch.CHProfileSelectorTest;
+import com.graphhopper.routing.lm.LMProfileSelectorTest;
+import com.graphhopper.routing.util.EncodingManager;
+import com.graphhopper.routing.util.HintsMap;
+import com.graphhopper.util.Parameters;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * So far this test is only testing the profile selection in the absence of CH/LM profiles. For CH/LM profile selection
+ *
+ * @see CHProfileSelectorTest
+ * @see LMProfileSelectorTest
+ */
+public class ProfileResolverTest {
+    @Test
+    public void defaultVehicle() {
+        ProfileResolver profileResolver = new ProfileResolver(
+                EncodingManager.create("car,foot,bike"),
+                Arrays.asList(
+                        new ProfileConfig("my_bike").setVehicle("bike"),
+                        new ProfileConfig("your_car").setVehicle("car")
+                ),
+                Collections.<CHProfileConfig>emptyList(), Collections.<LMProfileConfig>emptyList());
+        // without specifying the vehicle we get an error, because there are multiple matches
+        assertMultiMatchError(profileResolver, new HintsMap(), "There are multiple profiles matching your request");
+        // use vehicle to specify profile
+        assertEquals("your_car", profileResolver.resolveProfile(new HintsMap().setVehicle("car")).getName());
+        assertEquals("my_bike", profileResolver.resolveProfile(new HintsMap().setVehicle("bike")).getName());
+    }
+
+    @Test
+    public void defaultWeighting() {
+        ProfileResolver profileResolver = new ProfileResolver(
+                EncodingManager.create("bike,car,foot"),
+                Arrays.asList(
+                        new ProfileConfig("fast_bike").setVehicle("bike").setWeighting("fastest"),
+                        new ProfileConfig("short_bike").setVehicle("bike").setWeighting("shortest")
+                ),
+                Collections.<CHProfileConfig>emptyList(), Collections.<LMProfileConfig>emptyList());
+        // without specifying the weighting we get an error, because there are multiple matches
+        assertMultiMatchError(profileResolver, new HintsMap(), "There are multiple profiles matching your request");
+        // use weighting to specify profile
+        assertEquals("short_bike", profileResolver.resolveProfile(new HintsMap().setWeighting("shortest")).getName());
+        assertEquals("fast_bike", profileResolver.resolveProfile(new HintsMap().setWeighting("fastest")).getName());
+    }
+
+    @Test
+    public void missingProfiles() {
+        ProfileResolver profileResolver = new ProfileResolver(
+                EncodingManager.create("car,bike"),
+                Arrays.asList(
+                        new ProfileConfig("fast_bike").setVehicle("bike").setWeighting("fastest"),
+                        new ProfileConfig("short_bike").setVehicle("bike").setWeighting("shortest")
+                ),
+                Collections.<CHProfileConfig>emptyList(), Collections.<LMProfileConfig>emptyList());
+        // there is a car encoder but no associated profile
+        assertProfileNotFound(profileResolver, new HintsMap().setVehicle("car"));
+        // if we do not specify a vehicle or weighting we even have multiple matches
+        assertMultiMatchError(profileResolver, new HintsMap(), "There are multiple profiles matching your request");
+        // if we specify the weighting its clear which profile we want
+        assertEquals("short_bike", profileResolver.resolveProfile(new HintsMap().setWeighting("shortest")).getName());
+        // setting the vehicle to bike is not enough
+        assertMultiMatchError(profileResolver, new HintsMap().setVehicle("bike"), "There are multiple profiles matching your request");
+        // if we set the weighting as well it works
+        assertEquals("fast_bike", profileResolver.resolveProfile(new HintsMap().setVehicle("bike").setWeighting("fastest")).getName());
+        assertEquals("short_bike", profileResolver.resolveProfile(new HintsMap().setVehicle("bike").setWeighting("shortest")).getName());
+    }
+
+    @Test
+    public void edgeBasedAndTurnCosts() {
+        ProfileResolver profileResolver = new ProfileResolver(
+                EncodingManager.create("foot"),
+                Collections.singletonList(new ProfileConfig("profile").setVehicle("foot").setWeighting("fastest")),
+                Collections.<CHProfileConfig>emptyList(), Collections.<LMProfileConfig>emptyList());
+
+        assertProfileNotFound(profileResolver, new HintsMap().putObject(Parameters.Routing.EDGE_BASED, true));
+        assertEquals("profile", profileResolver.resolveProfile(new HintsMap()).getName());
+        assertEquals("profile", profileResolver.resolveProfile(new HintsMap().putObject(Parameters.Routing.EDGE_BASED, false)).getName());
+    }
+
+    @Test
+    public void defaultVehicleAllAlgos() {
+        final String profile1 = "foot_profile";
+        final String profile2 = "car_profile";
+        final String vehicle1 = "foot";
+        final String vehicle2 = "car";
+        final String weighting = "shortest";
+
+        ProfileResolver profileResolver = new ProfileResolver(
+                EncodingManager.create(vehicle1 + "," + vehicle2),
+                Arrays.asList(
+                        new ProfileConfig(profile1).setVehicle(vehicle1).setWeighting(weighting),
+                        new ProfileConfig(profile2).setVehicle(vehicle2).setWeighting(weighting)
+                ),
+                Arrays.asList(new CHProfileConfig(profile1), new CHProfileConfig(profile2)),
+                Arrays.asList(new LMProfileConfig(profile1), new LMProfileConfig(profile2))
+        );
+        // when we do not specify vehicle/weighting, we get an error because there are multiple matches
+        HintsMap hints = new HintsMap();
+        assertMultiMatchError(profileResolver, hints, "There are multiple CH profiles matching your request");
+        assertMultiMatchError(profileResolver, hints.putObject(Parameters.CH.DISABLE, true), "There are multiple LM profiles matching your request");
+        assertMultiMatchError(profileResolver, hints.putObject(Parameters.Landmark.DISABLE, true), "There are multiple profiles matching your request");
+
+        // using the weighting is not enough, because its the same for both profiles
+        hints = new HintsMap().setWeighting("shortest");
+        assertMultiMatchError(profileResolver, hints, "There are multiple CH profiles matching your request");
+        assertMultiMatchError(profileResolver, hints.putObject(Parameters.CH.DISABLE, true), "There are multiple LM profiles matching your request");
+        assertMultiMatchError(profileResolver, hints.putObject(Parameters.Landmark.DISABLE, true), "There are multiple profiles matching your request");
+
+        // using the vehicle to select one of the profiles works
+        hints = new HintsMap().setVehicle(vehicle1);
+        assertEquals(profile1, profileResolver.resolveProfile(hints).getName());
+        assertEquals(profile1, profileResolver.resolveProfile(hints.putObject(Parameters.CH.DISABLE, true)).getName());
+        assertEquals(profile1, profileResolver.resolveProfile(hints.putObject(Parameters.Landmark.DISABLE, true)).getName());
+    }
+
+    private void assertMultiMatchError(ProfileResolver profileResolver, HintsMap hints, String... expectedErrors) {
+        if (expectedErrors.length == 0) {
+            throw new IllegalArgumentException("there must be at least one expected error");
+        }
+        try {
+            profileResolver.resolveProfile(hints);
+            fail();
+        } catch (IllegalArgumentException e) {
+            for (String expectedError : expectedErrors) {
+                assertTrue(e.getMessage().contains(expectedError), e.getMessage());
+            }
+        }
+    }
+
+    private void assertProfileNotFound(ProfileResolver profileResolver, HintsMap hints) {
+        try {
+            profileResolver.resolveProfile(hints);
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertTrue(e.getMessage().contains("Cannot find matching profile for your request"), e.getMessage());
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/core/src/test/java/com/graphhopper/routing/RoutingAlgorithmIT.java b/core/src/test/java/com/graphhopper/routing/RoutingAlgorithmIT.java
index 3e86f1f72..fd3c42bdf 100644
--- a/core/src/test/java/com/graphhopper/routing/RoutingAlgorithmIT.java
+++ b/core/src/test/java/com/graphhopper/routing/RoutingAlgorithmIT.java
@@ -18,6 +18,7 @@
 package com.graphhopper.routing;
 
 import com.graphhopper.GraphHopper;
+import com.graphhopper.config.LMProfileConfig;
 import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.reader.PrincetonReader;
 import com.graphhopper.routing.util.EncodingManager;
@@ -25,7 +26,6 @@ import com.graphhopper.routing.util.HintsMap;
 import com.graphhopper.routing.util.TestAlgoCollector.AlgoHelperEntry;
 import com.graphhopper.routing.util.TraversalMode;
 import com.graphhopper.routing.weighting.Weighting;
-import com.graphhopper.storage.CHProfile;
 import com.graphhopper.storage.Directory;
 import com.graphhopper.storage.GraphBuilder;
 import com.graphhopper.storage.GraphHopperStorage;
@@ -36,10 +36,7 @@ import com.graphhopper.util.StopWatch;
 import org.junit.Test;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Random;
+import java.util.*;
 import java.util.zip.GZIPInputStream;
 
 import static com.graphhopper.util.Parameters.Algorithms.*;
@@ -62,8 +59,11 @@ public class RoutingAlgorithmIT {
         ProfileConfig profile = new ProfileConfig("profile").setVehicle(hints.getVehicle()).setWeighting(hints.getWeighting()).setTurnCosts(tMode.isEdgeBased());
         Weighting weighting = hopper.createWeighting(profile, hints);
 
-        HintsMap defaultHints = new HintsMap().putObject(Parameters.CH.DISABLE, true).putObject(Parameters.Landmark.DISABLE, true)
-                .setVehicle(hints.getVehicle()).setWeighting(hints.getWeighting());
+        HintsMap defaultHints = new HintsMap()
+                .putObject(Parameters.CH.DISABLE, true)
+                .putObject(Parameters.Landmark.DISABLE, true)
+                .setVehicle(hints.getVehicle())
+                .setWeighting(hints.getWeighting());
 
         AlgorithmOptions defaultOpts = AlgorithmOptions.start(new AlgorithmOptions("", weighting, tMode)).hints(defaultHints).build();
         List<AlgoHelperEntry> algos = new ArrayList<>();
@@ -92,17 +92,17 @@ public class RoutingAlgorithmIT {
             final HintsMap chHints = new HintsMap(defaultHints);
             chHints.putObject(Parameters.CH.DISABLE, false);
             chHints.putObject(Parameters.Routing.EDGE_BASED, tMode.isEdgeBased());
-            CHProfile pickedProfile = new ProfileResolver().selectCHProfile(hopper.getCHPreparationHandler().getCHProfiles(), chHints);
-            algos.add(new AlgoHelperEntry(ghStorage.getCHGraph(pickedProfile),
-                    AlgorithmOptions.start(dijkstrabiOpts).hints(chHints).build(), idx, "dijkstrabi|ch|algos|" + hints.getWeighting()) {
+            ProfileConfig pickedProfile = new ProfileResolver(hopper.getEncodingManager(), hopper.getProfiles(), hopper.getCHPreparationHandler().getCHProfileConfigs(), Collections.<LMProfileConfig>emptyList()).selectProfileCH(chHints);
+            algos.add(new AlgoHelperEntry(ghStorage.getCHGraph(pickedProfile.getName()),
+                    AlgorithmOptions.start(dijkstrabiOpts).hints(chHints).build(), idx, "dijkstrabi|ch|prepare|" + hints.getWeighting()) {
                 @Override
                 public RoutingAlgorithmFactory createRoutingFactory() {
                     return hopper.getAlgorithmFactory(chHints.getVehicle() + "_profile", false, true);
                 }
             });
 
-            algos.add(new AlgoHelperEntry(ghStorage.getCHGraph(pickedProfile),
-                    AlgorithmOptions.start(astarbiOpts).hints(chHints).build(), idx, "astarbi|ch|algos|" + hints.getWeighting()) {
+            algos.add(new AlgoHelperEntry(ghStorage.getCHGraph(pickedProfile.getName()),
+                    AlgorithmOptions.start(astarbiOpts).hints(chHints).build(), idx, "astarbi|ch|prepare|" + hints.getWeighting()) {
                 @Override
                 public RoutingAlgorithmFactory createRoutingFactory() {
                     return hopper.getAlgorithmFactory(chHints.getVehicle() + "_profile", false, true);
diff --git a/core/src/test/java/com/graphhopper/routing/ch/CHProfileSelectorTest.java b/core/src/test/java/com/graphhopper/routing/ch/CHProfileSelectorTest.java
index 9c1bc268b..4583b2bde 100644
--- a/core/src/test/java/com/graphhopper/routing/ch/CHProfileSelectorTest.java
+++ b/core/src/test/java/com/graphhopper/routing/ch/CHProfileSelectorTest.java
@@ -18,11 +18,11 @@
 
 package com.graphhopper.routing.ch;
 
+import com.graphhopper.config.CHProfileConfig;
+import com.graphhopper.config.LMProfileConfig;
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.routing.ProfileResolver;
 import com.graphhopper.routing.util.*;
-import com.graphhopper.routing.weighting.*;
-import com.graphhopper.storage.CHProfile;
-import com.graphhopper.storage.TurnCostStorage;
 import com.graphhopper.util.Parameters;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -36,208 +36,245 @@ import static org.junit.jupiter.api.Assertions.*;
 
 public class CHProfileSelectorTest {
 
-    private static final String MULTIPLE_EDGE_BASED_ERROR = "There are multiple edge-based CH profiles matching your request. You need to specify the profile you want to use explicitly";
-    private static final String MULTIPLE_MATCHES_ERROR = "There are multiple CH profiles matching your request. Use the `weighting`,`vehicle`,`edge_based` and/or `u_turn_costs` parameters to be more specific";
-    private static final String NO_MATCH_ERROR = "Cannot find matching CH profile for your request";
+    private static final String MULTIPLE_MATCHES_ERROR = "There are multiple CH profiles matching your request. Use the `weighting`,`vehicle`,`turn_costs` and/or `u_turn_costs` parameters to be more specific";
+    private static final String NO_MATCH_ERROR = "Cannot find matching profile that supports CH for your request";
 
-    private Weighting weightingFastestCar;
-    private Weighting weightingFastestCarEdge;
-    private Weighting weightingFastestCarEdge10;
-    private Weighting weightingFastestCarEdge30;
-    private Weighting weightingFastestCarEdge50;
-    private Weighting weightingFastestBike;
-    private Weighting weightingFastestBikeEdge40;
-    private Weighting weightingShortestCar;
-    private Weighting weightingShortestBike;
+    private ProfileConfig fastCar;
+    private ProfileConfig fastCarEdge;
+    private ProfileConfig fastCarEdge10;
+    private ProfileConfig fastCarEdge30;
+    private ProfileConfig fastCarEdge50;
+    private ProfileConfig fastBike;
+    private ProfileConfig fastBikeEdge40;
+    private ProfileConfig shortCar;
+    private ProfileConfig shortBike;
+    private EncodingManager encodingManager;
 
     @BeforeEach
     public void setup() {
         FlagEncoder carEncoder = new CarFlagEncoder();
         FlagEncoder bikeEncoder = new BikeFlagEncoder();
-        EncodingManager.create(carEncoder, bikeEncoder);
-        TurnCostStorage turnCostStorage = new TurnCostStorage(null, null);
-        weightingFastestCar = new FastestWeighting(carEncoder);
-        weightingFastestCarEdge = new FastestWeighting(carEncoder, new DefaultTurnCostProvider(carEncoder, turnCostStorage));
-        weightingFastestCarEdge10 = new FastestWeighting(carEncoder, new DefaultTurnCostProvider(carEncoder, turnCostStorage, 10));
-        weightingFastestCarEdge30 = new FastestWeighting(carEncoder, new DefaultTurnCostProvider(carEncoder, turnCostStorage, 30));
-        weightingFastestCarEdge50 = new FastestWeighting(carEncoder, new DefaultTurnCostProvider(carEncoder, turnCostStorage, 50));
-        weightingFastestBike = new FastestWeighting(bikeEncoder);
-        weightingFastestBikeEdge40 = new FastestWeighting(bikeEncoder, new DefaultTurnCostProvider(bikeEncoder, turnCostStorage, 40));
-        weightingShortestCar = new ShortestWeighting(carEncoder);
-        weightingShortestBike = new ShortestWeighting(bikeEncoder);
+        encodingManager = EncodingManager.create(carEncoder, bikeEncoder);
+        fastCar = new ProfileConfig("fast_car").setWeighting("fastest").setVehicle("car").setTurnCosts(false);
+        fastCarEdge = new ProfileConfig("fast_car_edge").setWeighting("fastest").setVehicle("car").setTurnCosts(true);
+        fastCarEdge10 = new ProfileConfig("fast_car_edge10").setWeighting("fastest").setVehicle("car").setTurnCosts(true).putHint(Parameters.Routing.U_TURN_COSTS, 10);
+        fastCarEdge30 = new ProfileConfig("fast_car_edge30").setWeighting("fastest").setVehicle("car").setTurnCosts(true).putHint(Parameters.Routing.U_TURN_COSTS, 30);
+        fastCarEdge50 = new ProfileConfig("fast_car_edge50").setWeighting("fastest").setVehicle("car").setTurnCosts(true).putHint(Parameters.Routing.U_TURN_COSTS, 50);
+        fastBike = new ProfileConfig("fast_bike").setWeighting("fastest").setVehicle("bike").setTurnCosts(false);
+        fastBikeEdge40 = new ProfileConfig("fast_bike_edge40").setWeighting("fastest").setVehicle("bike").setTurnCosts(true).putHint(Parameters.Routing.U_TURN_COSTS, 40);
+        shortCar = new ProfileConfig("short_car").setWeighting("shortest").setVehicle("car").setTurnCosts(false);
+        shortBike = new ProfileConfig("short_bike").setWeighting("shortest").setVehicle("bike").setTurnCosts(false);
     }
 
     @Test
     public void onlyNodeBasedPresent() {
-        List<CHProfile> chProfiles = Collections.singletonList(
-                CHProfile.nodeBased(weightingFastestCar)
+        List<ProfileConfig> profiles = Collections.singletonList(
+                fastCar
         );
-        assertCHProfileSelectionError(NO_MATCH_ERROR, chProfiles, true, null);
-        assertCHProfileSelectionError(NO_MATCH_ERROR, chProfiles, true, 20);
-        assertProfileFound(chProfiles.get(0), chProfiles, false, null);
-        assertCHProfileSelectionError(NO_MATCH_ERROR, chProfiles, false, 20);
-        assertProfileFound(chProfiles.get(0), chProfiles, null, null);
-        assertCHProfileSelectionError(NO_MATCH_ERROR, chProfiles, null, 30);
-        String error = assertCHProfileSelectionError(NO_MATCH_ERROR, chProfiles, "foot", "fastest", false, null);
-        assertTrue(error.contains("requested:  fastest|foot|edge_based=false|u_turn_costs=*"), error);
-        assertTrue(error.contains("available: [fastest|car|edge_based=false]"), error);
+        List<CHProfileConfig> chProfiles = Collections.singletonList(
+                new CHProfileConfig("fast_car")
+        );
+        assertCHProfileSelectionError(NO_MATCH_ERROR, profiles, chProfiles, true, null);
+        assertCHProfileSelectionError(NO_MATCH_ERROR, profiles, chProfiles, true, 20);
+        assertProfileFound(profiles.get(0), profiles, chProfiles, false, null);
+        assertCHProfileSelectionError(NO_MATCH_ERROR, profiles, chProfiles, false, 20);
+        assertProfileFound(profiles.get(0), profiles, chProfiles, null, null);
+        assertCHProfileSelectionError(NO_MATCH_ERROR, profiles, chProfiles, null, 30);
+        String error = assertCHProfileSelectionError(NO_MATCH_ERROR, profiles, chProfiles, "foot", "fastest", false, null);
+        assertTrue(error.contains("requested:  fastest|foot|turn_costs=false|u_turn_costs=*"), error);
+        assertTrue(error.contains("available: [fastest|car|turn_costs=false]"), error);
     }
 
     @Test
     public void onlyEdgeBasedPresent() {
-        List<CHProfile> chProfiles = Collections.singletonList(
-                CHProfile.edgeBased(weightingFastestCarEdge)
-        );
-        assertCHProfileSelectionError(NO_MATCH_ERROR, chProfiles, false, null);
-        assertCHProfileSelectionError(NO_MATCH_ERROR, chProfiles, false, 20);
-        assertProfileFound(chProfiles.get(0), chProfiles, true, null);
-        assertProfileFound(chProfiles.get(0), chProfiles, null, null);
+        List<ProfileConfig> profiles = Collections.singletonList(fastCarEdge);
+        List<CHProfileConfig> chProfiles = Collections.singletonList(new CHProfileConfig("fast_car_edge"));
+        assertCHProfileSelectionError(NO_MATCH_ERROR, profiles, chProfiles, false, null);
+        assertCHProfileSelectionError(NO_MATCH_ERROR, profiles, chProfiles, false, 20);
+        assertProfileFound(profiles.get(0), profiles, chProfiles, true, null);
+        assertProfileFound(profiles.get(0), profiles, chProfiles, null, null);
     }
 
     @Test
     public void edgeAndNodePresent() {
-        List<CHProfile> chProfiles = Arrays.asList(
-                CHProfile.nodeBased(weightingFastestCar),
-                CHProfile.edgeBased(weightingFastestCarEdge)
+        List<ProfileConfig> profiles = Arrays.asList(
+                fastCar,
+                fastCarEdge
+        );
+        List<CHProfileConfig> chProfiles = Arrays.asList(
+                new CHProfileConfig("fast_car"),
+                new CHProfileConfig("fast_car_edge")
         );
         // in case edge-based is not specified we prefer the edge-based profile over the node-based one
-        assertProfileFound(chProfiles.get(1), chProfiles, null, null);
-        assertProfileFound(chProfiles.get(0), chProfiles, false, null);
-        assertProfileFound(chProfiles.get(1), chProfiles, true, null);
+        assertProfileFound(profiles.get(1), profiles, chProfiles, null, null);
+        assertProfileFound(profiles.get(0), profiles, chProfiles, false, null);
+        assertProfileFound(profiles.get(1), profiles, chProfiles, true, null);
     }
 
     @Test
     public void multipleEdgeBased() {
-        List<CHProfile> chProfiles = Arrays.asList(
-                CHProfile.nodeBased(weightingFastestCar),
-                CHProfile.edgeBased(weightingFastestCarEdge30),
-                CHProfile.edgeBased(weightingFastestCarEdge50)
+        List<ProfileConfig> profiles = Arrays.asList(
+                fastCar,
+                fastCarEdge30,
+                fastCarEdge50
+        );
+        List<CHProfileConfig> chProfiles = Arrays.asList(
+                new CHProfileConfig("fast_car"),
+                new CHProfileConfig("fast_car_edge30"),
+                new CHProfileConfig("fast_car_edge50")
         );
-        // since there are multiple edge-based profiles we will get an error no matter if we do not specify the u-turn
-        // costs, specify some that do not exist or even specify the right u-turn costs, because we no longer allow
-        // choosing between multiple edge-based profiles without giving the profile name explicitly
-        assertCHProfileSelectionError(MULTIPLE_EDGE_BASED_ERROR, chProfiles, true, null);
-        assertCHProfileSelectionError(MULTIPLE_EDGE_BASED_ERROR, chProfiles, true, 40);
-        assertCHProfileSelectionError(MULTIPLE_EDGE_BASED_ERROR, chProfiles, true, 30);
+        // when no u-turns are specified we throw
+        assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, profiles, chProfiles, true, null);
+        // when we request one that does not exist we throw
+        assertCHProfileSelectionError(NO_MATCH_ERROR, profiles, chProfiles, true, 40);
+        // when we request one that exists it works
+        assertProfileFound(profiles.get(1), profiles, chProfiles, true, 30);
 
         // without specifying edge-based we also get an error
-        assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, chProfiles, null, null);
-        assertCHProfileSelectionError(MULTIPLE_EDGE_BASED_ERROR, chProfiles, null, 40);
-        assertCHProfileSelectionError(MULTIPLE_EDGE_BASED_ERROR, chProfiles, null, 30);
+        assertProfileFound(profiles.get(1), profiles, chProfiles, null, 30);
+        assertCHProfileSelectionError(NO_MATCH_ERROR, profiles, chProfiles, null, 40);
+        String error = assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, profiles, chProfiles, null, null);
+        assertTrue(error.contains("requested:  fastest|car|turn_costs=*|u_turn_costs=*"), error);
+        assertTrue(error.contains("matched:   [fastest|car|turn_costs=false, fastest|car|turn_costs=true|u_turn_costs=30, fastest|car|turn_costs=true|u_turn_costs=50]"), error);
+        assertTrue(error.contains("available: [fastest|car|turn_costs=false, fastest|car|turn_costs=true|u_turn_costs=30, fastest|car|turn_costs=true|u_turn_costs=50]"), error);
     }
 
     @Test
     public void missingVehicleOrWeighting() {
         // when we do not set the weighting and/or the car but it can be derived from the profile the profile is returned
-        List<CHProfile> chProfiles = Collections.singletonList(CHProfile.nodeBased(weightingFastestCar));
-        assertProfileFound(chProfiles.get(0), chProfiles, "car", "fastest", null, null);
-        assertProfileFound(chProfiles.get(0), chProfiles, "car", "", null, null);
-        assertProfileFound(chProfiles.get(0), chProfiles, "", "fastest", null, null);
-        assertProfileFound(chProfiles.get(0), chProfiles, "", "", null, null);
+        List<ProfileConfig> profiles = Collections.singletonList(fastCar);
+        List<CHProfileConfig> chProfiles = Collections.singletonList(new CHProfileConfig("fast_car"));
+        assertProfileFound(profiles.get(0), profiles, chProfiles, "car", "fastest", null, null);
+        assertProfileFound(profiles.get(0), profiles, chProfiles, "car", "", null, null);
+        assertProfileFound(profiles.get(0), profiles, chProfiles, "", "fastest", null, null);
+        assertProfileFound(profiles.get(0), profiles, chProfiles, "", "", null, null);
     }
 
     @Test
     public void missingVehicleOrWeighting_otherVehicleAndCar() {
-        List<CHProfile> chProfiles = Collections.singletonList(CHProfile.nodeBased(weightingShortestBike));
-        assertProfileFound(chProfiles.get(0), chProfiles, "bike", "shortest", null, null);
-        assertProfileFound(chProfiles.get(0), chProfiles, "bike", "", null, null);
-        assertProfileFound(chProfiles.get(0), chProfiles, "", "shortest", null, null);
-        assertProfileFound(chProfiles.get(0), chProfiles, "", "", null, null);
+        List<ProfileConfig> profiles = Collections.singletonList(shortBike);
+        List<CHProfileConfig> chProfiles = Collections.singletonList(new CHProfileConfig("short_bike"));
+        assertProfileFound(profiles.get(0), profiles, chProfiles, "bike", "shortest", null, null);
+        assertProfileFound(profiles.get(0), profiles, chProfiles, "bike", "", null, null);
+        assertProfileFound(profiles.get(0), profiles, chProfiles, "", "shortest", null, null);
+        assertProfileFound(profiles.get(0), profiles, chProfiles, "", "", null, null);
     }
 
 
     @Test
     public void missingVehicleMultipleProfiles() {
-        List<CHProfile> chProfiles = Arrays.asList(
-                CHProfile.nodeBased(weightingFastestBike),
-                CHProfile.nodeBased(weightingShortestBike),
-                CHProfile.edgeBased(weightingFastestBikeEdge40)
+        List<ProfileConfig> profiles = Arrays.asList(
+                fastBike,
+                shortBike,
+                fastBikeEdge40
+        );
+        List<CHProfileConfig> chProfiles = Arrays.asList(
+                new CHProfileConfig("fast_bike"),
+                new CHProfileConfig("short_bike"),
+                new CHProfileConfig("fast_bike_edge40")
         );
         // the vehicle is not given but only bike is used so its fine. note that we prefer edge-based because no edge_based parameter is specified
-        assertProfileFound(chProfiles.get(2), chProfiles, "", "fastest", null, null);
+        assertProfileFound(profiles.get(2), profiles, chProfiles, "", "fastest", null, null);
         // if we do not specify the weighting its not clear what to return -> there is an error
-        assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, chProfiles, "", "", null, null);
+        assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, profiles, chProfiles, "", "", null, null);
         // if we do not specify the weighting but edge_based=true its clear what to return because for edge-based there is only one weighting
-        assertProfileFound(chProfiles.get(2), chProfiles, "", "", true, null);
+        assertProfileFound(profiles.get(2), profiles, chProfiles, "", "", true, null);
         // ... for edge_based=false this is an error because there are two node-based profiles
-        assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, chProfiles, "", "", false, null);
+        assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, profiles, chProfiles, "", "", false, null);
     }
 
     @Test
     public void missingWeightingMultipleProfiles() {
-        List<CHProfile> chProfiles = Arrays.asList(
-                CHProfile.nodeBased(weightingFastestBike),
-                CHProfile.edgeBased(weightingFastestCarEdge10),
-                CHProfile.edgeBased(weightingFastestBikeEdge40)
+        List<ProfileConfig> profiles = Arrays.asList(
+                fastBike,
+                fastCarEdge10,
+                fastBikeEdge40
+        );
+        List<CHProfileConfig> chProfiles = Arrays.asList(
+                new CHProfileConfig("fast_bike"),
+                new CHProfileConfig("fast_car_edge10"),
+                new CHProfileConfig("fast_bike_edge40")
         );
         // the weighting is not given but only fastest is used so its fine. note that we prefer edge-based because no edge_based parameter is specified
-        assertProfileFound(chProfiles.get(2), chProfiles, "bike", "", null, null);
+        assertProfileFound(profiles.get(2), profiles, chProfiles, "bike", "", null, null);
         // if we do not specify the vehicle its not clear what to return -> there is an error
-        assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, chProfiles, "", "", null, null);
+        assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, profiles, chProfiles, "", "", null, null);
         // if we do not specify the vehicle but edge_based=false its clear what to return because for node-based there is only one weighting
-        assertProfileFound(chProfiles.get(0), chProfiles, "", "", false, null);
+        assertProfileFound(profiles.get(0), profiles, chProfiles, "", "", false, null);
         // ... for edge_based=true this is an error, because there are two edge_based profiles
-        assertCHProfileSelectionError(MULTIPLE_EDGE_BASED_ERROR, chProfiles, "", "", true, null);
-        // ... and its even an error if we specify the (correct) u-turn costs, because we no longer allow distinguishing the profile this way
-        assertCHProfileSelectionError(MULTIPLE_EDGE_BASED_ERROR, chProfiles, "", "", true, 10);
+        assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, profiles, chProfiles, "", "", true, null);
+        // ... we can however get a clear match if we specify the u-turn costs
+        assertProfileFound(profiles.get(1), profiles, chProfiles, "", "", true, 10);
     }
 
     @Test
     public void multipleVehiclesMissingWeighting() {
         // this is a common use-case, there are multiple vehicles for one weighting
         EncodingManager em = EncodingManager.create("car,bike,motorcycle,bike2,foot");
-        List<CHProfile> chProfiles = new ArrayList<>();
+        List<ProfileConfig> profiles = new ArrayList<>();
+        List<CHProfileConfig> chProfiles = new ArrayList<>();
         for (FlagEncoder encoder : em.fetchEdgeEncoders()) {
-            chProfiles.add(CHProfile.nodeBased(new ShortFastestWeighting(encoder, 1)));
+            profiles.add(new ProfileConfig(encoder.toString()).setVehicle(encoder.toString()).setWeighting("short_fastest").setTurnCosts(false));
+            chProfiles.add(new CHProfileConfig(encoder.toString()));
         }
         // we do not specify the weighting but this is ok, because there is only one in use
         String weighting = "";
-        assertProfileFound(chProfiles.get(0), chProfiles, "car", weighting, null, null);
-        assertProfileFound(chProfiles.get(1), chProfiles, "bike", weighting, null, null);
-        assertProfileFound(chProfiles.get(2), chProfiles, "motorcycle", weighting, null, null);
-        assertProfileFound(chProfiles.get(3), chProfiles, "bike2", weighting, null, null);
-        assertProfileFound(chProfiles.get(4), chProfiles, "foot", weighting, null, null);
+        assertProfileFound(profiles.get(0), profiles, chProfiles, "car", weighting, null, null);
+        assertProfileFound(profiles.get(1), profiles, chProfiles, "bike", weighting, null, null);
+        assertProfileFound(profiles.get(2), profiles, chProfiles, "motorcycle", weighting, null, null);
+        assertProfileFound(profiles.get(3), profiles, chProfiles, "bike2", weighting, null, null);
+        assertProfileFound(profiles.get(4), profiles, chProfiles, "foot", weighting, null, null);
     }
 
 
     @Test
     public void missingVehicle_multiplePossibilities_throws() {
-        List<CHProfile> chProfiles = Arrays.asList(
-                CHProfile.nodeBased(weightingFastestBike), CHProfile.nodeBased(weightingFastestCar)
+        List<ProfileConfig> profiles = Arrays.asList(
+                fastBike,
+                fastCar
         );
-        assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, chProfiles, "", "fastest", null, null);
+        List<CHProfileConfig> chProfiles = Arrays.asList(
+                new CHProfileConfig("fast_bike"),
+                new CHProfileConfig("fast_car")
+        );
+        assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, profiles, chProfiles, "", "fastest", null, null);
     }
 
     @Test
     public void missingWeighting_multiplePossibilities_throws() {
-        List<CHProfile> chProfiles = Arrays.asList(
-                CHProfile.nodeBased(weightingFastestBike), CHProfile.nodeBased(weightingShortestBike)
+        List<ProfileConfig> profiles = Arrays.asList(
+                fastBike,
+                shortBike
+        );
+        List<CHProfileConfig> chProfiles = Arrays.asList(
+                new CHProfileConfig("fast_bike"),
+                new CHProfileConfig("short_bike")
         );
-        assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, chProfiles, "bike", "", null, null);
+        assertCHProfileSelectionError(MULTIPLE_MATCHES_ERROR, profiles, chProfiles, "bike", "", null, null);
     }
 
-    private void assertProfileFound(CHProfile expectedProfile, List<CHProfile> profiles, Boolean edgeBased, Integer uTurnCosts) {
-        assertProfileFound(expectedProfile, profiles, "car", "fastest", edgeBased, uTurnCosts);
+    private void assertProfileFound(ProfileConfig expectedProfile, List<ProfileConfig> profiles, List<CHProfileConfig> chProfiles, Boolean edgeBased, Integer uTurnCosts) {
+        assertProfileFound(expectedProfile, profiles, chProfiles, "car", "fastest", edgeBased, uTurnCosts);
     }
 
-    private void assertProfileFound(CHProfile expectedProfile, List<CHProfile> profiles, String vehicle, String weighting, Boolean edgeBased, Integer uTurnCosts) {
+    private void assertProfileFound(ProfileConfig expectedProfile, List<ProfileConfig> profiles, List<CHProfileConfig> chProfiles, String vehicle, String weighting, Boolean edgeBased, Integer uTurnCosts) {
         HintsMap hintsMap = createHintsMap(vehicle, weighting, edgeBased, uTurnCosts);
         try {
-            CHProfile selectedProfile = new ProfileResolver().selectCHProfile(profiles, hintsMap);
+            ProfileConfig selectedProfile = new ProfileResolver(encodingManager, profiles, chProfiles, Collections.<LMProfileConfig>emptyList()).selectProfileCH(hintsMap);
             assertEquals(expectedProfile, selectedProfile);
         } catch (IllegalArgumentException e) {
             fail("no profile found\nexpected: " + expectedProfile + "\nerror: " + e.getMessage());
         }
     }
 
-    private String assertCHProfileSelectionError(String expectedError, List<CHProfile> profiles, Boolean edgeBased, Integer uTurnCosts) {
-        return assertCHProfileSelectionError(expectedError, profiles, "car", "fastest", edgeBased, uTurnCosts);
+    private String assertCHProfileSelectionError(String expectedError, List<ProfileConfig> profiles, List<CHProfileConfig> chProfiles, Boolean edgeBased, Integer uTurnCosts) {
+        return assertCHProfileSelectionError(expectedError, profiles, chProfiles, "car", "fastest", edgeBased, uTurnCosts);
     }
 
-    private String assertCHProfileSelectionError(String expectedError, List<CHProfile> profiles, String vehicle, String weighting, Boolean edgeBased, Integer uTurnCosts) {
+    private String assertCHProfileSelectionError(String expectedError, List<ProfileConfig> profiles, List<CHProfileConfig> chProfiles, String vehicle, String weighting, Boolean edgeBased, Integer uTurnCosts) {
         HintsMap hintsMap = createHintsMap(vehicle, weighting, edgeBased, uTurnCosts);
         try {
-            new ProfileResolver().selectCHProfile(profiles, hintsMap);
+            new ProfileResolver(encodingManager, profiles, chProfiles, Collections.<LMProfileConfig>emptyList()).selectProfileCH(hintsMap);
             fail("There should have been an error");
             return "";
         } catch (IllegalArgumentException e) {
diff --git a/core/src/test/java/com/graphhopper/routing/lm/LMProfileSelectorTest.java b/core/src/test/java/com/graphhopper/routing/lm/LMProfileSelectorTest.java
index 445e41222..37cb870ae 100644
--- a/core/src/test/java/com/graphhopper/routing/lm/LMProfileSelectorTest.java
+++ b/core/src/test/java/com/graphhopper/routing/lm/LMProfileSelectorTest.java
@@ -18,15 +18,17 @@
 
 package com.graphhopper.routing.lm;
 
+import com.graphhopper.config.CHProfileConfig;
+import com.graphhopper.config.LMProfileConfig;
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.routing.ProfileResolver;
 import com.graphhopper.routing.util.*;
-import com.graphhopper.routing.weighting.FastestWeighting;
-import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.util.Parameters;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 import static org.junit.jupiter.api.Assertions.*;
@@ -34,91 +36,142 @@ import static org.junit.jupiter.api.Assertions.*;
 
 public class LMProfileSelectorTest {
 
-    private static final String MULTIPLE_MATCHES_ERROR = "There are multiple LM profiles matching your request. Use the `weighting` and `vehicle` parameters to be more specific";
+    private static final String MULTIPLE_MATCHES_ERROR = "There are multiple LM profiles matching your request. Use the `weighting`, `vehicle` and `turn_costs` parameters to be more specific";
     private static final String NO_MATCH_ERROR = "Cannot find matching LM profile for your request";
 
-    private Weighting weightingFastestCar;
-    private Weighting weightingFastestBike;
+    private EncodingManager encodingManager;
+    private ProfileConfig fastCar;
+    private ProfileConfig fastCarEdge;
+    private ProfileConfig fastBike;
+    private ProfileConfig shortBikeEdge;
 
     @BeforeEach
     public void setup() {
         FlagEncoder carEncoder = new CarFlagEncoder();
         FlagEncoder bikeEncoder = new BikeFlagEncoder();
-        EncodingManager.create(carEncoder, bikeEncoder);
-        weightingFastestCar = new FastestWeighting(carEncoder);
-        weightingFastestBike = new FastestWeighting(bikeEncoder);
+        encodingManager = EncodingManager.create(carEncoder, bikeEncoder);
+        fastCar = new ProfileConfig("fast_car").setVehicle("car").setWeighting("fastest").setTurnCosts(false);
+        fastCarEdge = new ProfileConfig("fast_car_edge").setVehicle("car").setWeighting("fastest").setTurnCosts(true);
+        fastBike = new ProfileConfig("fast_bike").setVehicle("bike").setWeighting("fastest").setTurnCosts(false);
+        shortBikeEdge = new ProfileConfig("short_bike_edge").setVehicle("bike").setWeighting("shortest").setTurnCosts(true);
     }
 
     @Test
     public void singleProfile() {
-        List<LMProfile> lmProfiles = Arrays.asList(
-                new LMProfile("profile1", weightingFastestCar)
+        List<ProfileConfig> profiles = Arrays.asList(
+                fastCar
+        );
+        List<LMProfileConfig> lmProfiles = Arrays.asList(
+                new LMProfileConfig("fast_car")
         );
         // as long as we do not request something that does not fit the existing profile we have a match
-        assertProfileFound(lmProfiles.get(0), lmProfiles, null, null, null, null);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, "car", null, null, null);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, null, "fastest", null, null);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, "car", "fastest", null, null);
-
-        // requesting edge_based or u_turn_costs should not lead to a non-match
-        assertProfileFound(lmProfiles.get(0), lmProfiles, null, null, true, null);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, null, null, false, null);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, null, null, null, 54);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, null, null, true, 54);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, "car", null, true, 54);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, null, "fastest", true, 54);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, "car", "fastest", true, null);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, "car", "fastest", true, 54);
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, null, null, null, null);
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, "car", null, null, null);
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, null, "fastest", null, null);
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, "car", "fastest", null, null);
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, "car", "fastest", false, null);
+
+        // requesting edge_based when the profile is not edge_based leads to a non-match
+        assertLMProfileSelectionError(NO_MATCH_ERROR, profiles, lmProfiles, null, null, true, null);
+        assertLMProfileSelectionError(NO_MATCH_ERROR, profiles, lmProfiles, "car", null, true, null);
+        assertLMProfileSelectionError(NO_MATCH_ERROR, profiles, lmProfiles, null, "fastest", true, null);
+        assertLMProfileSelectionError(NO_MATCH_ERROR, profiles, lmProfiles, "car", "fastest", true, null);
+
+        // requesting u_turn_costs should not lead to a non-match
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, null, null, null, 54);
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, null, null, false, 54);
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, "car", null, false, 54);
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, null, "fastest", false, 54);
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, "car", "fastest", false, 54);
 
         // if we request something that does not fit we do not get a match
-        String error = assertLMProfileSelectionError(NO_MATCH_ERROR, lmProfiles, "bike", null, null, null);
-        assertTrue(error.contains("available: [fastest|car]"), error);
-        assertLMProfileSelectionError(NO_MATCH_ERROR, lmProfiles, "car", "shortest", null, null);
-        assertLMProfileSelectionError(NO_MATCH_ERROR, lmProfiles, null, "shortest", null, null);
-        assertLMProfileSelectionError(NO_MATCH_ERROR, lmProfiles, "truck", "short_fastest", null, null);
+        String error = assertLMProfileSelectionError(NO_MATCH_ERROR, profiles, lmProfiles, "bike", null, null, null);
+        assertTrue(error.contains("requested:  *|bike|turn_costs=*"), error);
+        assertTrue(error.contains("available: [fastest|car|turn_costs=false]"), error);
+        assertLMProfileSelectionError(NO_MATCH_ERROR, profiles, lmProfiles, "car", "shortest", null, null);
+        assertLMProfileSelectionError(NO_MATCH_ERROR, profiles, lmProfiles, "car", null, true, null);
+        assertLMProfileSelectionError(NO_MATCH_ERROR, profiles, lmProfiles, null, "shortest", null, null);
+        assertLMProfileSelectionError(NO_MATCH_ERROR, profiles, lmProfiles, "truck", "short_fastest", null, null);
     }
 
     @Test
     public void multipleProfiles() {
-        List<LMProfile> lmProfiles = Arrays.asList(
-                new LMProfile("profile1", weightingFastestCar),
-                new LMProfile("profile2", weightingFastestBike)
+        List<ProfileConfig> profiles = Arrays.asList(
+                fastCar,
+                fastBike
         );
-
-        assertProfileFound(lmProfiles.get(0), lmProfiles, "car", null, null, null);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, "car", "fastest", null, null);
-        assertProfileFound(lmProfiles.get(1), lmProfiles, "bike", null, null, null);
-        assertProfileFound(lmProfiles.get(1), lmProfiles, "bike", "fastest", null, null);
+        List<LMProfileConfig> lmProfiles = Arrays.asList(
+                new LMProfileConfig("fast_car"),
+                new LMProfileConfig("fast_bike")
+        );
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, "car", null, null, null);
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, "car", "fastest", null, null);
+        assertProfileFound(profiles.get(1), profiles, lmProfiles, "bike", null, null, null);
+        assertProfileFound(profiles.get(1), profiles, lmProfiles, "bike", "fastest", null, null);
 
         // not specific enough
-        String error = assertLMProfileSelectionError(MULTIPLE_MATCHES_ERROR, lmProfiles, null, "fastest", null, null);
-        assertTrue(error.contains("requested:  fastest|*"), error);
-        assertTrue(error.contains("matched:   [fastest|car, fastest|bike]"), error);
-        assertTrue(error.contains("available: [fastest|car, fastest|bike]"), error);
-        assertLMProfileSelectionError(NO_MATCH_ERROR, lmProfiles, null, "shortest", null, null);
-
-        // edge_based/u_turn_costs is set, but lm should not really care
-        assertProfileFound(lmProfiles.get(0), lmProfiles, "car", null, null, null);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, "car", null, true, null);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, "car", null, null, 54);
-        assertProfileFound(lmProfiles.get(0), lmProfiles, "car", null, false, 64);
+        String error = assertLMProfileSelectionError(MULTIPLE_MATCHES_ERROR, profiles, lmProfiles, null, "fastest", null, null);
+        assertTrue(error.contains("requested:  fastest|*|turn_costs=*"), error);
+        assertTrue(error.contains("matched:   [fastest|car|turn_costs=false, fastest|bike|turn_costs=false]"), error);
+        assertTrue(error.contains("available: [fastest|car|turn_costs=false, fastest|bike|turn_costs=false]"), error);
+        assertLMProfileSelectionError(NO_MATCH_ERROR, profiles, lmProfiles, null, "shortest", null, null);
+
+        // u_turn_costs is set, but lm should not really care
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, "car", null, null, 54);
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, "car", null, false, 64);
     }
 
+    @Test
+    public void withAndWithoutTurnCosts() {
+        List<ProfileConfig> profiles = Arrays.asList(
+                fastCar,
+                fastBike,
+                fastCarEdge,
+                shortBikeEdge
+        );
+        List<LMProfileConfig> lmProfiles = Arrays.asList(
+                new LMProfileConfig("fast_car"),
+                new LMProfileConfig("fast_bike"),
+                new LMProfileConfig("fast_car_edge"),
+                new LMProfileConfig("short_bike_edge")
+        );
+        // edge_based can be used to select between otherwise identical profiles
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, "car", null, false, null);
+        assertProfileFound(profiles.get(2), profiles, lmProfiles, "car", null, true, null);
+
+        // in case there are two matching profiles and they are only different by turn_costs=true/false the one with
+        // turn costs is preferred (just like for CH)
+        assertProfileFound(profiles.get(2), profiles, lmProfiles, "car", null, null, null);
+
+        // not being specific enough leads to multiple matching profiles error
+        assertLMProfileSelectionError(MULTIPLE_MATCHES_ERROR, profiles, lmProfiles, null, "fastest", null, null);
+
+        // we get an error if we request turn_costs that are not supported
+        assertLMProfileSelectionError(NO_MATCH_ERROR, profiles, lmProfiles, "bike", "fastest", true, null);
+        assertLMProfileSelectionError(NO_MATCH_ERROR, profiles, lmProfiles, "bike", "shortest", false, null);
+        assertLMProfileSelectionError(NO_MATCH_ERROR, profiles, lmProfiles, null, "shortest", false, null);
+
+        // vehicle&weighting are derived from the available profiles in case they are not given
+        assertProfileFound(profiles.get(0), profiles, lmProfiles, "car", null, false, null);
+        assertProfileFound(profiles.get(1), profiles, lmProfiles, "bike", null, false, null);
+        assertProfileFound(profiles.get(2), profiles, lmProfiles, null, "fastest", true, null);
+        assertProfileFound(profiles.get(3), profiles, lmProfiles, null, "shortest", true, null);
+    }
 
-    private void assertProfileFound(LMProfile expectedProfile, List<LMProfile> profiles, String vehicle, String weighting, Boolean edgeBased, Integer uTurnCosts) {
+    private void assertProfileFound(ProfileConfig expectedProfile, List<ProfileConfig> profiles, List<LMProfileConfig> lmProfiles, String vehicle, String weighting, Boolean edgeBased, Integer uTurnCosts) {
         HintsMap hintsMap = createHintsMap(vehicle, weighting, edgeBased, uTurnCosts);
         try {
-            LMProfile selectedProfile = new ProfileResolver().selectLMProfile(profiles, hintsMap);
+            ProfileConfig selectedProfile = new ProfileResolver(encodingManager, profiles, Collections.<CHProfileConfig>emptyList(), lmProfiles).selectProfileLM(hintsMap);
             assertEquals(expectedProfile, selectedProfile);
         } catch (IllegalArgumentException e) {
             fail("no profile found\nexpected: " + expectedProfile + "\nerror: " + e.getMessage());
         }
     }
 
-    private String assertLMProfileSelectionError(String expectedError, List<LMProfile> profiles, String vehicle, String weighting, Boolean edgeBased, Integer uTurnCosts) {
+    private String assertLMProfileSelectionError(String expectedError, List<ProfileConfig> profiles, List<LMProfileConfig> lmProfiles, String vehicle, String weighting, Boolean edgeBased, Integer uTurnCosts) {
         HintsMap hintsMap = createHintsMap(vehicle, weighting, edgeBased, uTurnCosts);
         try {
-            new ProfileResolver().selectLMProfile(profiles, hintsMap);
+            new ProfileResolver(encodingManager, profiles, Collections.<CHProfileConfig>emptyList(), lmProfiles).selectProfileLM(hintsMap);
             fail("There should have been an error");
             return "";
         } catch (IllegalArgumentException e) {
diff --git a/reader-gtfs/src/test/java/com/graphhopper/AnotherAgencyIT.java b/reader-gtfs/src/test/java/com/graphhopper/AnotherAgencyIT.java
index 653b4e215..0780cceac 100644
--- a/reader-gtfs/src/test/java/com/graphhopper/AnotherAgencyIT.java
+++ b/reader-gtfs/src/test/java/com/graphhopper/AnotherAgencyIT.java
@@ -19,6 +19,7 @@
 package com.graphhopper;
 
 import com.carrotsearch.hppc.IntHashSet;
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.reader.gtfs.*;
 import com.graphhopper.routing.util.AllEdgesIterator;
 import com.graphhopper.routing.weighting.FastestWeighting;
@@ -53,7 +54,11 @@ public class AnotherAgencyIT {
         ghConfig.putObject("graph.flag_encoders", "car,foot");
         ghConfig.putObject("graph.location", GRAPH_LOC);
         ghConfig.putObject("datareader.file", "files/beatty.osm");
-        ghConfig.putObject("gtfs.file", "files/sample-feed.zip,files/another-sample-feed.zip");
+        ghConfig.putObject("gtfs.file", "files/sample-feed.zip,files/another-sample-feed.zip").
+                setProfiles(Arrays.asList(
+                        new ProfileConfig("car").setVehicle("car").setWeighting("fastest"),
+                        new ProfileConfig("foot").setVehicle("foot").setWeighting("fastest")
+                ));
         Helper.removeDir(new File(GRAPH_LOC));
         graphHopperGtfs = new GraphHopperGtfs(ghConfig);
         graphHopperGtfs.init(ghConfig);
diff --git a/reader-gtfs/src/test/java/com/graphhopper/ExtendedRouteTypeIT.java b/reader-gtfs/src/test/java/com/graphhopper/ExtendedRouteTypeIT.java
index 18d9b0fc4..6ef82a0c5 100644
--- a/reader-gtfs/src/test/java/com/graphhopper/ExtendedRouteTypeIT.java
+++ b/reader-gtfs/src/test/java/com/graphhopper/ExtendedRouteTypeIT.java
@@ -18,6 +18,7 @@
 
 package com.graphhopper;
 
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.reader.gtfs.GraphHopperGtfs;
 import com.graphhopper.reader.gtfs.PtRouteResource;
 import com.graphhopper.reader.gtfs.Request;
@@ -30,6 +31,7 @@ import org.junit.Test;
 import java.io.File;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
+import java.util.Arrays;
 
 import static com.graphhopper.reader.gtfs.GtfsHelper.time;
 import static org.junit.Assert.assertEquals;
@@ -47,7 +49,11 @@ public class ExtendedRouteTypeIT {
         GraphHopperConfig ghConfig = new GraphHopperConfig();
         ghConfig.putObject("graph.flag_encoders", "car,foot");
         ghConfig.putObject("graph.location", GRAPH_LOC);
-        ghConfig.putObject("gtfs.file", "files/another-sample-feed-extended-route-type.zip");
+        ghConfig.putObject("gtfs.file", "files/another-sample-feed-extended-route-type.zip").
+                setProfiles(Arrays.asList(
+                        new ProfileConfig("car").setVehicle("car").setWeighting("fastest"),
+                        new ProfileConfig("foot").setVehicle("foot").setWeighting("fastest")
+                ));
         Helper.removeDir(new File(GRAPH_LOC));
         graphHopperGtfs = new GraphHopperGtfs(ghConfig);
         graphHopperGtfs.init(ghConfig);
diff --git a/reader-gtfs/src/test/java/com/graphhopper/GraphHopperGtfsIT.java b/reader-gtfs/src/test/java/com/graphhopper/GraphHopperGtfsIT.java
index edbb7996a..52ef7e1ad 100644
--- a/reader-gtfs/src/test/java/com/graphhopper/GraphHopperGtfsIT.java
+++ b/reader-gtfs/src/test/java/com/graphhopper/GraphHopperGtfsIT.java
@@ -18,6 +18,7 @@
 
 package com.graphhopper;
 
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.reader.gtfs.GraphHopperGtfs;
 import com.graphhopper.reader.gtfs.PtRouteResource;
 import com.graphhopper.reader.gtfs.Request;
@@ -34,6 +35,7 @@ import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.ZoneId;
+import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -53,7 +55,11 @@ public class GraphHopperGtfsIT {
         GraphHopperConfig ghConfig = new GraphHopperConfig();
         ghConfig.putObject("graph.flag_encoders", "car,foot");
         ghConfig.putObject("graph.location", GRAPH_LOC);
-        ghConfig.putObject("gtfs.file", "files/sample-feed.zip");
+        ghConfig.putObject("gtfs.file", "files/sample-feed.zip").
+                setProfiles(Arrays.asList(
+                        new ProfileConfig("car").setVehicle("car").setWeighting("fastest"),
+                        new ProfileConfig("foot").setVehicle("foot").setWeighting("fastest")
+                ));
         Helper.removeDir(new File(GRAPH_LOC));
         graphHopperGtfs = new GraphHopperGtfs(ghConfig);
         graphHopperGtfs.init(ghConfig);
diff --git a/reader-gtfs/src/test/java/com/graphhopper/GraphHopperMultimodalIT.java b/reader-gtfs/src/test/java/com/graphhopper/GraphHopperMultimodalIT.java
index ad5e7e476..a8656fc0c 100644
--- a/reader-gtfs/src/test/java/com/graphhopper/GraphHopperMultimodalIT.java
+++ b/reader-gtfs/src/test/java/com/graphhopper/GraphHopperMultimodalIT.java
@@ -18,6 +18,7 @@
 
 package com.graphhopper;
 
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.reader.gtfs.GraphHopperGtfs;
 import com.graphhopper.reader.gtfs.PtRouteResource;
 import com.graphhopper.reader.gtfs.Request;
@@ -32,6 +33,7 @@ import java.io.File;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.ZoneId;
+import java.util.Arrays;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -49,7 +51,11 @@ public class GraphHopperMultimodalIT {
         ghConfig.putObject("graph.flag_encoders", "car,foot");
         ghConfig.putObject("datareader.file", "files/beatty.osm");
         ghConfig.putObject("gtfs.file", "files/sample-feed.zip");
-        ghConfig.putObject("graph.location", GRAPH_LOC);
+        ghConfig.putObject("graph.location", GRAPH_LOC).
+                setProfiles(Arrays.asList(
+                        new ProfileConfig("car").setVehicle("car").setWeighting("fastest"),
+                        new ProfileConfig("foot").setVehicle("foot").setWeighting("fastest")
+                ));
         Helper.removeDir(new File(GRAPH_LOC));
         graphHopperGtfs = new GraphHopperGtfs(ghConfig);
         graphHopperGtfs.init(ghConfig);
diff --git a/reader-gtfs/src/test/java/com/graphhopper/RealtimeIT.java b/reader-gtfs/src/test/java/com/graphhopper/RealtimeIT.java
index 4aacd1486..562296c81 100644
--- a/reader-gtfs/src/test/java/com/graphhopper/RealtimeIT.java
+++ b/reader-gtfs/src/test/java/com/graphhopper/RealtimeIT.java
@@ -19,6 +19,7 @@
 package com.graphhopper;
 
 import com.google.transit.realtime.GtfsRealtime;
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.reader.gtfs.GraphHopperGtfs;
 import com.graphhopper.reader.gtfs.PtRouteResource;
 import com.graphhopper.reader.gtfs.Request;
@@ -31,6 +32,7 @@ import org.junit.Test;
 import java.io.File;
 import java.math.BigDecimal;
 import java.time.*;
+import java.util.Collections;
 
 import static com.google.transit.realtime.GtfsRealtime.TripDescriptor.ScheduleRelationship.ADDED;
 import static com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate.ScheduleRelationship.SCHEDULED;
@@ -50,7 +52,8 @@ public class RealtimeIT {
         GraphHopperConfig ghConfig = new GraphHopperConfig();
         ghConfig.putObject("graph.flag_encoders", "car,foot");
         ghConfig.putObject("gtfs.file", "files/sample-feed.zip");
-        ghConfig.putObject("graph.location", GRAPH_LOC);
+        ghConfig.putObject("graph.location", GRAPH_LOC).
+                setProfiles(Collections.singletonList(new ProfileConfig("car").setVehicle("car").setWeighting("fastest")));
         Helper.removeDir(new File(GRAPH_LOC));
         graphHopperGtfs = new GraphHopperGtfs(ghConfig);
         graphHopperGtfs.init(ghConfig);
diff --git a/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java b/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java
index 917484a10..394894106 100644
--- a/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java
+++ b/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java
@@ -30,6 +30,7 @@ import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.routing.util.HintsMap;
 import com.graphhopper.routing.util.parsers.OSMMaxSpeedParser;
 import com.graphhopper.routing.util.parsers.OSMRoadEnvironmentParser;
+import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.IntsRef;
 import com.graphhopper.util.*;
 import com.graphhopper.util.Parameters.CH;
@@ -102,8 +103,7 @@ public class GraphHopperIT {
         hopper.importOrLoad();
         GHRequest req = new GHRequest(43.727687, 7.418737, 43.74958, 7.436566)
                 .setAlgorithm(algo)
-                .setVehicle(vehicle)
-                .setWeighting(weighting);
+                .setProfile("profile");
         req.putHint(CH.DISABLE, !withCH);
         GHResponse rsp = hopper.route(req);
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
@@ -120,15 +120,17 @@ public class GraphHopperIT {
 
     @Test
     public void testMonacoWithInstructions() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "shortest";
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true).
                 importOrLoad();
 
         GHResponse rsp = hopper.route(new GHRequest(43.727687, 7.418737, 43.74958, 7.436566).
-                setAlgorithm(ASTAR).setVehicle(vehicle).setWeighting(weighting));
+                setAlgorithm(ASTAR).setProfile(profile));
 
         // identify the number of counts to compare with CH foot route
         assertEquals(699, rsp.getHints().getLong("visited_nodes.sum", 0));
@@ -170,14 +172,16 @@ public class GraphHopperIT {
 
     @Test
     public void withoutInstructions() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "shortest";
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true).
                 importOrLoad();
 
-        GHRequest request = new GHRequest().setAlgorithm(ASTAR).setVehicle(vehicle).setWeighting(weighting);
+        GHRequest request = new GHRequest().setAlgorithm(ASTAR).setProfile(profile);
         request.addPoint(new GHPoint(43.729584, 7.410965));
         request.addPoint(new GHPoint(43.732499, 7.426758));
         request.getHints().putObject("instructions", true);
@@ -193,10 +197,12 @@ public class GraphHopperIT {
 
     @Test
     public void testUTurn() {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "shortest";
         GraphHopper hopper = createGraphHopper(vehicle).
-                setOSMFile(MONACO);
+                setOSMFile(MONACO).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting));
         hopper.importOrLoad();
         Translation tr = hopper.getTranslationMap().getWithFallBack(Locale.US);
 
@@ -205,7 +211,7 @@ public class GraphHopperIT {
         request.addPoint(new GHPoint(43.743887, 7.431151), 200);
         request.addPoint(new GHPoint(43.744007, 7.431076));
 
-        request.setAlgorithm(ASTAR).setVehicle(vehicle).setWeighting(weighting);
+        request.setAlgorithm(ASTAR).setProfile(profile);
         GHResponse rsp = hopper.route(request);
 
         assertFalse(rsp.hasErrors());
@@ -260,8 +266,7 @@ public class GraphHopperIT {
 
         if (ch) {
             GHRequest req = new GHRequest(43.727687, 7.418737, 43.74958, 7.436566).
-                    setWeighting(weighting).
-                    setVehicle(vehicle);
+                    setProfile(profile);
             req.putHint(CH.DISABLE, false);
             req.putHint(Landmark.DISABLE, true);
             GHResponse rsp = hopper.route(req);
@@ -276,8 +281,7 @@ public class GraphHopperIT {
 
         if (lm) {
             GHRequest req = new GHRequest(43.727687, 7.418737, 43.74958, 7.436566).
-                    setVehicle(vehicle).
-                    setWeighting(weighting).
+                    setProfile(profile).
                     setAlgorithm(Parameters.Algorithms.ASTAR_BI);
             req.putHint(CH.DISABLE, true);
             req.putHint(Landmark.DISABLE, false);
@@ -293,8 +297,7 @@ public class GraphHopperIT {
 
         // flexible
         GHRequest req = new GHRequest(43.727687, 7.418737, 43.74958, 7.436566).
-                setVehicle(vehicle).
-                setWeighting(weighting);
+                setProfile(profile);
         req.putHint(CH.DISABLE, true);
         req.putHint(Landmark.DISABLE, true);
         GHResponse rsp = hopper.route(req);
@@ -336,15 +339,17 @@ public class GraphHopperIT {
 
     @Test
     public void testAlternativeRoutes() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "shortest";
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true).
                 importOrLoad();
 
         GHRequest req = new GHRequest(43.729057, 7.41251, 43.740298, 7.423561).
-                setAlgorithm(ALT_ROUTE).setVehicle(vehicle).setWeighting(weighting);
+                setAlgorithm(ALT_ROUTE).setProfile(profile);
 
         GHResponse rsp = hopper.route(req);
         assertFalse(rsp.hasErrors());
@@ -366,15 +371,17 @@ public class GraphHopperIT {
 
     @Test
     public void testAlternativeRoutesBike() {
+        final String profile = "profile";
         final String vehicle = "bike";
         final String weighting = "fastest";
 
         GraphHopper hopper = createGraphHopper(vehicle).
-                setOSMFile(BAYREUTH);
+                setOSMFile(BAYREUTH).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting));
         hopper.importOrLoad();
 
         GHRequest req = new GHRequest(50.028917, 11.496506, 49.985228, 11.600876).
-                setAlgorithm(ALT_ROUTE).setVehicle(vehicle).setWeighting(weighting);
+                setAlgorithm(ALT_ROUTE).setProfile(profile);
         req.putHint("alternative_route.max_paths", 3);
         GHResponse rsp = hopper.route(req);
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
@@ -390,16 +397,18 @@ public class GraphHopperIT {
 
     @Test
     public void testAlternativeRoutesCar() {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "fastest";
 
         GraphHopper hopper = createGraphHopper(vehicle).
-                setOSMFile(BAYREUTH);
+                setOSMFile(BAYREUTH).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting));
         hopper.importOrLoad();
 
         GHRequest req = new GHRequest(50.023513, 11.548862, 49.969441, 11.537876).
-                setAlgorithm(ALT_ROUTE).setVehicle(vehicle).setWeighting(weighting);
-        req.getHints().putObject("alternative_route.max_paths", 3);
+                setAlgorithm(ALT_ROUTE).setProfile(profile);
+        req.putHint("alternative_route.max_paths", 3);
         GHResponse rsp = hopper.route(req);
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
 
@@ -414,15 +423,17 @@ public class GraphHopperIT {
 
     @Test
     public void testPointHint() {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "fastest";
 
         GraphHopper hopper = createGraphHopper(vehicle).
-                setOSMFile(LAUF);
+                setOSMFile(LAUF).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting));
         hopper.importOrLoad();
 
         GHRequest req = new GHRequest(49.46553, 11.154669, 49.465244, 11.152577).
-                setVehicle(vehicle).setWeighting(weighting);
+                setProfile(profile);
 
         req.setPointHints(new ArrayList<>(asList("Laufamholzstraße, 90482, Nürnberg, Deutschland", "")));
         GHResponse rsp = hopper.route(req);
@@ -449,15 +460,17 @@ public class GraphHopperIT {
 
     @Test
     public void testNorthBayreuthDestination() {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "fastest";
 
         GraphHopper hopper = createGraphHopper(vehicle).
-                setOSMFile(BAYREUTH);
+                setOSMFile(BAYREUTH).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting));
         hopper.importOrLoad();
 
         GHRequest req = new GHRequest(49.985307, 11.50628, 49.985731, 11.507465).
-                setVehicle(vehicle).setWeighting(weighting);
+                setProfile(profile);
 
         GHResponse rsp = hopper.route(req);
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
@@ -466,16 +479,17 @@ public class GraphHopperIT {
 
     @Test
     public void testNorthBayreuthBlockedEdges() {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "fastest";
 
         GraphHopper hopper = createGraphHopper(vehicle).
-                setOSMFile(BAYREUTH);
+                setOSMFile(BAYREUTH).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting));
         hopper.importOrLoad();
 
         GHRequest req = new GHRequest(49.985272, 11.506151, 49.986107, 11.507202).
-                setVehicle(vehicle).
-                setWeighting(weighting);
+                setProfile(profile);
 
         GHResponse rsp = hopper.route(req);
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
@@ -488,8 +502,7 @@ public class GraphHopperIT {
         assertEquals(365, rsp.getBest().getDistance(), 1);
 
         req = new GHRequest(49.975845, 11.522598, 50.026821, 11.497364).
-                setVehicle(vehicle).
-                setWeighting(weighting);
+                setProfile(profile);
 
         rsp = hopper.route(req);
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
@@ -502,7 +515,7 @@ public class GraphHopperIT {
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
         assertEquals(13988, rsp.getBest().getDistance(), 1);
 
-        // Add blocked point to above area, to increase detour        
+        // Add blocked point to above area, to increase detour
         req.putHint(Routing.BLOCK_AREA, "50.017578,11.547527;" + someArea);
         rsp = hopper.route(req);
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
@@ -527,7 +540,7 @@ public class GraphHopperIT {
 
         // blocking works for all weightings
         req = new GHRequest(50.009504, 11.490669, 50.024726, 11.496162).
-                setVehicle(vehicle).setWeighting(weighting);
+                setProfile(profile);
         rsp = hopper.route(req);
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
         assertEquals(1807, rsp.getBest().getDistance(), 1);
@@ -539,8 +552,7 @@ public class GraphHopperIT {
 
         // query point and snapped point are different => block snapped point only => show that block_area changes lookup
         req = new GHRequest(49.984465, 11.507009, 49.986107, 11.507202).
-                setVehicle(vehicle).
-                setWeighting(weighting);
+                setProfile(profile);
         rsp = hopper.route(req);
         assertEquals(11.506, rsp.getBest().getWaypoints().getLongitude(0), 0.001);
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
@@ -554,8 +566,7 @@ public class GraphHopperIT {
 
         // first point is contained in block_area => error
         req = new GHRequest(49.979, 11.516, 49.986107, 11.507202).
-                setVehicle(vehicle).
-                setWeighting(weighting);
+                setProfile(profile);
         req.putHint(Routing.BLOCK_AREA, "49.981875,11.515818,49.979522,11.521407");
         rsp = hopper.route(req);
         assertTrue("expected errors", rsp.hasErrors());
@@ -563,10 +574,12 @@ public class GraphHopperIT {
 
     @Test
     public void testMonacoVia() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "shortest";
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true).
                 importOrLoad();
 
@@ -575,7 +588,7 @@ public class GraphHopperIT {
                 addPoint(new GHPoint(43.727687, 7.418737)).
                 addPoint(new GHPoint(43.74958, 7.436566)).
                 addPoint(new GHPoint(43.727687, 7.418737)).
-                setAlgorithm(ASTAR).setVehicle(vehicle).setWeighting(weighting));
+                setAlgorithm(ASTAR).setProfile(profile));
 
         PathWrapper arsp = rsp.getBest();
         assertEquals(6875.2, arsp.getDistance(), .1);
@@ -617,7 +630,7 @@ public class GraphHopperIT {
         rsp = hopper.route(new GHRequest().
                 addPoint(new GHPoint(43.727687, 7.418737)).
                 addPoint(new GHPoint(43.727687, 7.418737)).
-                setAlgorithm(ASTAR).setVehicle(vehicle).setWeighting(weighting));
+                setAlgorithm(ASTAR).setProfile(profile));
 
         arsp = rsp.getBest();
         assertEquals(0, arsp.getDistance(), .1);
@@ -631,7 +644,7 @@ public class GraphHopperIT {
                 addPoint(new GHPoint(43.727687, 7.418737)).
                 addPoint(new GHPoint(43.727687, 7.418737)).
                 addPoint(new GHPoint(43.727687, 7.418737)).
-                setAlgorithm(ASTAR).setVehicle(vehicle).setWeighting(weighting));
+                setAlgorithm(ASTAR).setProfile(profile));
 
         arsp = rsp.getBest();
         assertEquals(0, arsp.getDistance(), .1);
@@ -644,10 +657,12 @@ public class GraphHopperIT {
 
     @Test
     public void testMonacoPathDetails() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "shortest";
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true).
                 importOrLoad();
 
@@ -655,7 +670,7 @@ public class GraphHopperIT {
         request.addPoint(new GHPoint(43.727687, 7.418737));
         request.addPoint(new GHPoint(43.74958, 7.436566));
         request.addPoint(new GHPoint(43.727687, 7.418737));
-        request.setAlgorithm(ASTAR).setVehicle(vehicle).setWeighting(weighting);
+        request.setAlgorithm(ASTAR).setProfile(profile);
         request.setPathDetails(Collections.singletonList(Parameters.Details.AVERAGE_SPEED));
 
         GHResponse rsp = hopper.route(request);
@@ -673,17 +688,19 @@ public class GraphHopperIT {
 
     @Test
     public void testMonacoEnforcedDirection() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "fastest";
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true).
                 importOrLoad();
 
         GHRequest req = new GHRequest().
                 addPoint(new GHPoint(43.741069, 7.426854), 0.).
                 addPoint(new GHPoint(43.744445, 7.429483), 190.).
-                setVehicle(vehicle).setWeighting(weighting);
+                setProfile(profile);
         req.putHint(Routing.HEADING_PENALTY, "300");
         GHResponse rsp = hopper.route(req);
 
@@ -694,10 +711,12 @@ public class GraphHopperIT {
 
     @Test
     public void testMonacoMaxVisitedNodes() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "fastest";
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true).
                 importOrLoad();
 
@@ -706,7 +725,7 @@ public class GraphHopperIT {
         GHRequest req = new GHRequest().
                 addPoint(from).
                 addPoint(to).
-                setVehicle(vehicle).setWeighting(weighting);
+                setProfile(profile);
         req.putHint(Routing.MAX_VISITED_NODES, 5);
         GHResponse rsp = hopper.route(req);
 
@@ -716,7 +735,7 @@ public class GraphHopperIT {
         req = new GHRequest().
                 addPoint(from).
                 addPoint(to).
-                setVehicle(vehicle).setWeighting(weighting);
+                setProfile(profile);
         rsp = hopper.route(req);
 
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
@@ -724,10 +743,12 @@ public class GraphHopperIT {
 
     @Test
     public void testMonacoNonChMaxWaypointDistance() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "fastest";
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true).
                 importOrLoad();
 
@@ -737,7 +758,7 @@ public class GraphHopperIT {
         GHRequest req = new GHRequest().
                 addPoint(from).
                 addPoint(to).
-                setVehicle(vehicle).setWeighting(weighting);
+                setProfile(profile);
 
         // Fail since points are too far apart
         hopper.setNonChMaxWaypointDistance(1000);
@@ -756,10 +777,12 @@ public class GraphHopperIT {
 
     @Test
     public void testMonacoNonChMaxWaypointDistanceMultiplePoints() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "fastest";
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true).
                 importOrLoad();
 
@@ -771,7 +794,7 @@ public class GraphHopperIT {
                 addPoint(from).
                 addPoint(via).
                 addPoint(to).
-                setVehicle(vehicle).setWeighting(weighting);
+                setProfile(profile);
 
         // Fail since points are too far
         hopper.setNonChMaxWaypointDistance(1000);
@@ -794,10 +817,12 @@ public class GraphHopperIT {
 
     @Test
     public void testMonacoStraightVia() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "fastest";
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true).
                 importOrLoad();
 
@@ -805,7 +830,7 @@ public class GraphHopperIT {
                 addPoint(new GHPoint(43.741069, 7.426854)).
                 addPoint(new GHPoint(43.740371, 7.426946)).
                 addPoint(new GHPoint(43.740794, 7.427294)).
-                setVehicle(vehicle).setWeighting(weighting);
+                setProfile(profile);
         rq.putHint(Routing.PASS_THROUGH, true);
         GHResponse rsp = hopper.route(rq);
 
@@ -818,7 +843,7 @@ public class GraphHopperIT {
                 addPoint(new GHPoint(43.741069, 7.426854)).
                 addPoint(new GHPoint(43.741069, 7.426854)).
                 addPoint(new GHPoint(43.740371, 7.426946)).
-                setVehicle(vehicle).setWeighting(weighting);
+                setProfile(profile);
         rq.putHint(Routing.PASS_THROUGH, true);
         rsp = hopper.route(rq);
         assertEquals(91, rsp.getBest().getDistance(), 5.);
@@ -826,18 +851,20 @@ public class GraphHopperIT {
 
     @Test
     public void testSRTMWithInstructions() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "shortest";
 
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true);
 
         hopper.setElevationProvider(new SRTMProvider(DIR));
         hopper.importOrLoad();
 
         GHResponse rsp = hopper.route(new GHRequest(43.730729, 7.421288, 43.727697, 7.419199).
-                setAlgorithm(ASTAR).setVehicle(vehicle).setWeighting(weighting));
+                setAlgorithm(ASTAR).setProfile(profile));
 
         PathWrapper arsp = rsp.getBest();
         assertEquals(1625.4, arsp.getDistance(), .1);
@@ -877,6 +904,7 @@ public class GraphHopperIT {
 
     @Test
     public void testSRTMWithoutTunnelInterpolation() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "shortest";
 
@@ -884,6 +912,7 @@ public class GraphHopperIT {
                 .setOSMFile(MONACO)
                 .setStoreOnFlush(true)
                 .setGraphHopperLocation(GH_LOCATION)
+                .setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting))
                 .setEncodingManager(EncodingManager.start().add(new OSMRoadEnvironmentParser() {
                     @Override
                     public IntsRef handleWayTags(IntsRef edgeFlags, ReaderWay readerWay, boolean ferry, IntsRef relationFlags) {
@@ -897,7 +926,7 @@ public class GraphHopperIT {
 
         GHResponse rsp = hopper.route(new GHRequest(43.74056471749763, 7.4299266210693755,
                 43.73790260334179, 7.427984089259056).setAlgorithm(ASTAR)
-                .setVehicle(vehicle).setWeighting(weighting));
+                .setProfile(profile));
         PathWrapper arsp = rsp.getBest();
         assertEquals(356.5, arsp.getDistance(), .1);
         PointList pointList = arsp.getPoints();
@@ -914,11 +943,13 @@ public class GraphHopperIT {
 
     @Test
     public void testSRTMWithTunnelInterpolation() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "shortest";
 
         GraphHopper hopper = createGraphHopper("car,foot")
                 .setOSMFile(MONACO)
+                .setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting))
                 .setStoreOnFlush(true);
 
         hopper.setElevationProvider(new SRTMProvider(DIR));
@@ -926,7 +957,7 @@ public class GraphHopperIT {
 
         GHResponse rsp = hopper.route(new GHRequest(43.74056471749763, 7.4299266210693755,
                 43.73790260334179, 7.427984089259056).setAlgorithm(ASTAR)
-                .setVehicle(vehicle).setWeighting(weighting));
+                .setProfile(profile));
         PathWrapper arsp = rsp.getBest();
         // Without interpolation: 356.5
         assertEquals(351, arsp.getDistance(), .1);
@@ -944,18 +975,22 @@ public class GraphHopperIT {
 
     @Test
     public void testSkadiElevationProvider() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "shortest";
 
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
+                setProfiles(
+                        new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)
+                ).
                 setStoreOnFlush(true);
 
         hopper.setElevationProvider(new SkadiProvider(DIR));
         hopper.importOrLoad();
 
-        GHResponse rsp = hopper.route(new GHRequest(43.730729, 7.421288, 43.727697, 7.419199).
-                setAlgorithm(ASTAR).setVehicle(vehicle).setWeighting(weighting));
+        GHResponse rsp = hopper.route(new GHRequest(43.730729, 7.421288, 43.727697, 7.419199)
+                .setProfile(profile));
 
         PathWrapper arsp = rsp.getBest();
         assertEquals(1601.6, arsp.getDistance(), .1);
@@ -968,18 +1003,23 @@ public class GraphHopperIT {
 
     @Test
     public void testKremsCyclewayInstructionsWithWayTypeInfo() {
+        final String profile1 = "foot_profile";
+        final String profile2 = "bike_profile";
         final String vehicle1 = "foot";
         final String vehicle2 = "bike";
         final String weighting = "fastest";
 
         GraphHopper hopper = createGraphHopper(vehicle1 + "," + vehicle2).
                 setOSMFile(KREMS).
+                setProfiles(
+                        new ProfileConfig(profile1).setVehicle(vehicle1).setWeighting(weighting),
+                        new ProfileConfig(profile2).setVehicle(vehicle2).setWeighting(weighting)).
                 setStoreOnFlush(true).
                 importOrLoad();
 
         Translation tr = hopper.getTranslationMap().getWithFallBack(Locale.US);
         GHResponse rsp = hopper.route(new GHRequest(48.410987, 15.599492, 48.383419, 15.659294).
-                setVehicle(vehicle2).setWeighting(weighting));
+                setProfile(profile2));
         assertFalse(rsp.hasErrors());
         PathWrapper arsp = rsp.getBest();
         assertEquals(6932.2, arsp.getDistance(), .1);
@@ -1008,7 +1048,7 @@ public class GraphHopperIT {
 
         // do not return 'get off bike' for foot
         rsp = hopper.route(new GHRequest(48.410987, 15.599492, 48.411172, 15.600371).
-                setAlgorithm(ASTAR).setVehicle(vehicle1).setWeighting(weighting));
+                setAlgorithm(ASTAR).setProfile(profile1));
         assertFalse(rsp.hasErrors());
         il = rsp.getBest().getInstructions();
         assertEquals("continue onto Obere Landstraße", il.get(0).getTurnDescription(tr));
@@ -1017,6 +1057,8 @@ public class GraphHopperIT {
 
     @Test
     public void testRoundaboutInstructionsWithCH() {
+        final String profile1 = "my_profile";
+        final String profile2 = "your_profile";
         final String vehicle1 = "car";
         final String vehicle2 = "bike";
         final String weighting = "fastest";
@@ -1024,46 +1066,44 @@ public class GraphHopperIT {
         GraphHopper hopper = createGraphHopper(vehicle1 + "," + vehicle2).
                 setOSMFile(MONACO).
                 setProfiles(Arrays.asList(
-                        new ProfileConfig("my_profile").setVehicle(vehicle1).setWeighting(weighting),
-                        new ProfileConfig("your_profile").setVehicle(vehicle2).setWeighting(weighting))
+                        new ProfileConfig(profile1).setVehicle(vehicle1).setWeighting(weighting),
+                        new ProfileConfig(profile2).setVehicle(vehicle2).setWeighting(weighting))
                 ).
                 setStoreOnFlush(true);
         hopper.getCHPreparationHandler().setCHProfileConfigs(
-                new CHProfileConfig("my_profile"),
-                new CHProfileConfig("your_profile")
+                new CHProfileConfig(profile1),
+                new CHProfileConfig(profile2)
         );
         hopper.importOrLoad();
 
-        assertEquals(vehicle1, hopper.getDefaultVehicle().toString());
-
         assertEquals(2, hopper.getCHPreparationHandler().getPreparations().size());
 
         GHResponse rsp = hopper.route(new GHRequest(43.745084, 7.430513, 43.745247, 7.430347)
-                .setVehicle(vehicle1).setWeighting(weighting));
+                .setProfile(profile1));
 
         PathWrapper arsp = rsp.getBest();
         assertEquals(2, ((RoundaboutInstruction) arsp.getInstructions().get(1)).getExitNumber());
 
         rsp = hopper.route(new GHRequest(43.745968, 7.42907, 43.745832, 7.428614)
-                .setVehicle(vehicle1).setWeighting(weighting));
+                .setProfile(profile1));
         arsp = rsp.getBest();
         assertEquals(2, ((RoundaboutInstruction) arsp.getInstructions().get(1)).getExitNumber());
 
         rsp = hopper.route(new GHRequest(43.745948, 7.42914, 43.746173, 7.428834)
-                .setVehicle(vehicle1).setWeighting(weighting));
+                .setProfile(profile1));
         arsp = rsp.getBest();
         assertEquals(1, ((RoundaboutInstruction) arsp.getInstructions().get(1)).getExitNumber());
 
         rsp = hopper.route(new GHRequest(43.735817, 7.417096, 43.735666, 7.416587)
-                .setVehicle(vehicle1).setWeighting(weighting));
+                .setProfile(profile1));
         arsp = rsp.getBest();
         assertEquals(2, ((RoundaboutInstruction) arsp.getInstructions().get(1)).getExitNumber());
     }
 
     @Test
     public void testCircularJunctionInstructionsWithCH() {
-        String profile1 = "car_profile";
-        String profile2 = "bike_profile";
+        String profile1 = "profile1";
+        String profile2 = "profile2";
         String vehicle1 = "car";
         String vehicle2 = "bike";
         String weighting = "fastest";
@@ -1080,12 +1120,9 @@ public class GraphHopperIT {
         );
         hopper.importOrLoad();
 
-        assertEquals(vehicle1, hopper.getDefaultVehicle().toString());
-
         assertEquals(2, hopper.getCHPreparationHandler().getPreparations().size());
-
         GHResponse rsp = hopper.route(new GHRequest(52.513505, 13.350443, 52.513505, 13.350245)
-                .setVehicle(vehicle1).setWeighting(weighting));
+                .setProfile(profile1));
 
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
         Instruction instr = rsp.getBest().getInstructions().get(1);
@@ -1108,52 +1145,34 @@ public class GraphHopperIT {
                 setOSMFile(MONACO).
                 setProfiles(profiles).
                 setStoreOnFlush(true);
-        hopper.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig(profile1), new CHProfileConfig(profile2));
-        hopper.importOrLoad();
-        assertEquals(vehicle1, hopper.getDefaultVehicle().toString());
-        checkMultiVehiclesWithCH(hopper);
-        hopper.close();
-
-        hopper.clean();
-        // new instance, try different order, resulting only in different default vehicle
-        hopper = createGraphHopper(vehicle2 + ", " + vehicle1).
-                setOSMFile(MONACO).
-                setProfiles(profiles).
-                setStoreOnFlush(true);
-        hopper.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig(profile1), new CHProfileConfig(profile2));
+        hopper.getCHPreparationHandler().setCHProfileConfigs(
+                new CHProfileConfig(profile1),
+                new CHProfileConfig(profile2)
+        );
         hopper.importOrLoad();
-        assertEquals(vehicle2, hopper.getDefaultVehicle().toString());
-        checkMultiVehiclesWithCH(hopper);
-        hopper.close();
-    }
-
-    private void checkMultiVehiclesWithCH(GraphHopper hopper) {
         String str = hopper.getEncodingManager().toString();
         GHResponse rsp = hopper.route(new GHRequest(43.73005, 7.415707, 43.741522, 7.42826)
-                .setVehicle("car")
-                .setWeighting("fastest"));
+                .setProfile("profile2"));
         PathWrapper arsp = rsp.getBest();
         assertFalse("car routing for " + str + " should not have errors:" + rsp.getErrors(), rsp.hasErrors());
         assertEquals(207, arsp.getTime() / 1000f, 1);
         assertEquals(2838, arsp.getDistance(), 1);
 
         rsp = hopper.route(new GHRequest(43.73005, 7.415707, 43.741522, 7.42826)
-                .setVehicle("bike")
-                .setWeighting("fastest"));
+                .setProfile("profile1"));
         arsp = rsp.getBest();
         assertFalse("bike routing for " + str + " should not have errors:" + rsp.getErrors(), rsp.hasErrors());
         assertEquals(494, arsp.getTime() / 1000f, 1);
         assertEquals(2192, arsp.getDistance(), 1);
 
         rsp = hopper.route(new GHRequest(43.73005, 7.415707, 43.741522, 7.42826)
-                .setVehicle("foot")
-                .setWeighting("fastest"));
-        assertTrue("only bike and car were imported. foot request should fail", rsp.hasErrors());
+                .setProfile("profile3"));
+        assertTrue("only profile1 and profile2 exist, request for profile3 should fail", rsp.hasErrors());
 
         GHRequest req = new GHRequest().
                 addPoint(new GHPoint(43.741069, 7.426854), 0.).
                 addPoint(new GHPoint(43.744445, 7.429483), 190.).
-                setVehicle("bike").setWeighting("fastest");
+                setProfile("profile1");
 
         rsp = hopper.route(req);
         assertTrue("heading not allowed for CH enabled graph", rsp.hasErrors());
@@ -1182,7 +1201,7 @@ public class GraphHopperIT {
 
         // same query as in testMonacoWithInstructions
         GHResponse rsp = hopper.route(new GHRequest(43.727687, 7.418737, 43.74958, 7.436566).
-                setVehicle(vehicle).setWeighting(weighting));
+                setProfile(profile));
 
         PathWrapper bestPath = rsp.getBest();
         // identify the number of counts to compare with none-CH foot route which had nearly 700 counts
@@ -1206,16 +1225,18 @@ public class GraphHopperIT {
 
     @Test
     public void testRoundTour() {
+        final String profile = "profile";
         final String vehicle = "foot";
         final String weighting = "fastest";
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true).
                 importOrLoad();
 
         GHRequest rq = new GHRequest().
                 addPoint(new GHPoint(43.741069, 7.426854), 50).
-                setVehicle(vehicle).setWeighting(weighting).
+                setProfile(profile).
                 setAlgorithm(ROUND_TRIP);
         rq.putHint(RoundTrip.DISTANCE, 1000);
         rq.putHint(RoundTrip.SEED, 0);
@@ -1231,11 +1252,13 @@ public class GraphHopperIT {
 
     @Test
     public void testPathDetails1216() {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "fastest";
 
         GraphHopper hopper = createGraphHopper(vehicle).
-                setOSMFile(BAYREUTH);
+                setOSMFile(BAYREUTH).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting));
         hopper.importOrLoad();
 
         GHRequest req = new GHRequest().
@@ -1243,7 +1266,7 @@ public class GraphHopperIT {
                 // This is exactly between two edges with different speed values
                         addPoint(new GHPoint(49.984565, 11.499188)).
                         addPoint(new GHPoint(49.9847, 11.499612)).
-                        setVehicle(vehicle).setWeighting(weighting).
+                        setProfile(profile).
                         setPathDetails(Collections.singletonList(Parameters.Details.AVERAGE_SPEED));
 
         GHResponse rsp = hopper.route(req);
@@ -1252,16 +1275,18 @@ public class GraphHopperIT {
 
     @Test
     public void testPathDetailsSamePoint() {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "fastest";
         GraphHopper hopper = createGraphHopper(vehicle).
-                setOSMFile(BAYREUTH);
+                setOSMFile(BAYREUTH).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting));
         hopper.importOrLoad();
 
         GHRequest req = new GHRequest().
                 addPoint(new GHPoint(49.984352, 11.498802)).
                 addPoint(new GHPoint(49.984352, 11.498802)).
-                setVehicle(vehicle).setWeighting(weighting).
+                setProfile(profile).
                 setPathDetails(Collections.singletonList(Parameters.Details.AVERAGE_SPEED));
 
         GHResponse rsp = hopper.route(req);
@@ -1290,8 +1315,7 @@ public class GraphHopperIT {
         hopper.importOrLoad();
 
         GHRequest req = new GHRequest(43.727687, 7.418737, 43.74958, 7.436566).
-                setVehicle(vehicle).
-                setWeighting(weighting);
+                setProfile(profile);
         // request speed mode
         req.putHint(Landmark.DISABLE, true);
         req.putHint(CH.DISABLE, false);
@@ -1333,105 +1357,69 @@ public class GraphHopperIT {
     }
 
     @Test
-    public void testDefaultVehicle() {
-        final String profile1 = "foot_profile";
-        final String profile2 = "car_profile";
-        final String vehicle1 = "foot";
-        final String vehicle2 = "car";
-        final String weighting = "shortest";
-
-        GraphHopper hopper = createGraphHopper(vehicle1 + "," + vehicle2).
-                setOSMFile(MONACO).
-                setProfiles(
-                        new ProfileConfig(profile1).setVehicle(vehicle1).setWeighting(weighting),
-                        new ProfileConfig(profile2).setVehicle(vehicle2).setWeighting(weighting)
-                );
-
-        hopper.getCHPreparationHandler().
-                setCHProfileConfigs(new CHProfileConfig(profile1), new CHProfileConfig(profile2)).
-                setDisablingAllowed(true);
-
-        hopper.getLMPreparationHandler().
-                setLMProfileConfigs(new LMProfileConfig(profile1), new LMProfileConfig(profile2)).
-                setDisablingAllowed(true);
-
-        hopper.importOrLoad();
-        // we do not specify vehicle/weighting, but we get a clear match because the default vehicle will be used
-        HintsMap hints = new HintsMap().putObject(CH.DISABLE, false).putObject(Landmark.DISABLE, false);
-        ProfileConfig p = hopper.resolveProfile(hints);
-        assertEquals("foot_profile", p.getName());
-        assertEquals("foot", p.getVehicle());
-
-        p = hopper.resolveProfile(hints.putObject(CH.DISABLE, true));
-        assertEquals("foot_profile", p.getName());
-        assertEquals("foot", p.getVehicle());
-
-        p = hopper.resolveProfile(hints.putObject(Landmark.DISABLE, true));
-        assertEquals("unprepared_profile", p.getName());
-        assertEquals("foot", p.getVehicle());
-    }
-
-    @Test
-    public void testHintsForUnpreparedProfile() {
+    public void testCreateWeightingHintsMerging() {
         final String profile = "profile";
         final String vehicle = "mtb";
         final String weighting = "shortest";
 
         GraphHopper hopper = createGraphHopper(vehicle + "|turn_costs=true").
                 setOSMFile(MONACO).
-                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting).setTurnCosts(true));
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting).setTurnCosts(true).putHint(U_TURN_COSTS, 123));
         hopper.importOrLoad();
 
-        // since we are creating unprepared profiles on the fly we have to make sure they preserve all hints
-        HintsMap hints = new HintsMap().setVehicle(vehicle).setWeighting(weighting).putObject("abc", 22);
-        ProfileConfig p = hopper.resolveProfile(hints);
-        assertEquals(22, p.getHints().getInt("abc", -1));
-        assertEquals("unprepared_profile", p.getName());
+        // if we do not pass u_turn_costs with the request hints we get those from the profile
+        HintsMap hints = new HintsMap().setVehicle(vehicle).setWeighting(weighting);
+        Weighting w = hopper.createWeighting(hopper.getProfiles().get(0), hints);
+        assertEquals("shortest|mtb|u_turn_costs=123", w.toString());
 
-        hints = new HintsMap().setVehicle(vehicle).setWeighting(weighting).putObject("abc", 46);
-        p = hopper.resolveProfile(hints);
-        assertEquals("unprepared_profile", p.getName());
-        assertEquals(46, p.getHints().getInt("abc", -1));
+        // we can overwrite the u_turn_costs given in the profile
+        hints = new HintsMap().setVehicle(vehicle).setWeighting(weighting).putObject(U_TURN_COSTS, 46);
+        w = hopper.createWeighting(hopper.getProfiles().get(0), hints);
+        assertEquals("shortest|mtb|u_turn_costs=46", w.toString());
     }
 
     @Test
     public void testPreparedProfileNotAvailable() {
-        final String profile = "car_profile";
+        final String profile1 = "fast_profile";
+        final String profile2 = "short_fast_profile";
         final String vehicle = "car";
-        final String weighting = "fastest";
+        final String weighting1 = "fastest";
+        final String weighting2 = "short_fastest";
 
         GraphHopper hopper = createGraphHopper(vehicle).
                 setOSMFile(MONACO).
-                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
+                setProfiles(
+                        new ProfileConfig(profile1).setVehicle(vehicle).setWeighting(weighting1),
+                        new ProfileConfig(profile2).setVehicle(vehicle).setWeighting(weighting2)
+                ).
                 setStoreOnFlush(true);
 
         hopper.getCHPreparationHandler().
-                setCHProfileConfigs(new CHProfileConfig(profile)).
+                setCHProfileConfigs(new CHProfileConfig(profile1)).
                 setDisablingAllowed(true);
 
         hopper.getLMPreparationHandler().
-                setLMProfileConfigs(new LMProfileConfig(profile).setMaximumLMWeight(2000)).
+                setLMProfileConfigs(new LMProfileConfig(profile1).setMaximumLMWeight(2000)).
                 setDisablingAllowed(true);
 
         hopper.importOrLoad();
-        // request a weighting that was not prepared
+        // request a profile that was not prepared
         GHRequest req = new GHRequest(43.727687, 7.418737, 43.74958, 7.436566).
-                setVehicle(vehicle).
-                setWeighting("short_fastest");
+                setProfile(profile2);
 
         // try with CH
         req.putHint(CH.DISABLE, false);
         req.putHint(Landmark.DISABLE, false);
         GHResponse res = hopper.route(req);
         assertTrue(res.getErrors().toString(), res.hasErrors());
-        assertTrue("there should be an error", res.getErrors().get(0).getMessage().contains("Cannot find matching CH profile for your request"));
+        assertTrue(res.getErrors().toString(), res.getErrors().get(0).getMessage().contains("Cannot find CH preparation for the requested profile: 'short_fast_profile'"));
 
         // try with LM
         req.putHint(CH.DISABLE, true);
         req.putHint(Landmark.DISABLE, false);
         res = hopper.route(req);
         assertTrue(res.getErrors().toString(), res.hasErrors());
-        assertTrue("there should be an error", res.getErrors().get(0).getMessage().contains("Cannot find matching LM profile for your request"));
+        assertTrue(res.getErrors().toString(), res.getErrors().get(0).getMessage().contains("Cannot find LM preparation for the requested profile: 'short_fast_profile'"));
 
         // falling back to non-prepared algo works
         req.putHint(CH.DISABLE, true);
@@ -1460,8 +1448,7 @@ public class GraphHopperIT {
 
         // we can switch LM on/off
         GHRequest req = new GHRequest(43.727687, 7.418737, 43.74958, 7.436566).
-                setVehicle(vehicle).
-                setWeighting(weighting);
+                setProfile(profile);
 
         req.putHint(Landmark.DISABLE, false);
         GHResponse res = hopper.route(req);
@@ -1496,7 +1483,7 @@ public class GraphHopperIT {
             double lon1 = bounds.minLon + rnd.nextDouble() * (bounds.maxLon - bounds.minLon);
             double lon2 = bounds.minLon + rnd.nextDouble() * (bounds.maxLon - bounds.minLon);
             GHRequest req = new GHRequest(lat1, lon1, lat2, lon2);
-            req.getHints().putObject(Routing.EDGE_BASED, turnCosts);
+            req.setProfile(profile);
             req.getHints().putObject(CH.DISABLE, false).putObject(Landmark.DISABLE, true);
             PathWrapper pathCH = hopper.route(req).getBest();
             req.getHints().putObject(CH.DISABLE, true).putObject(Landmark.DISABLE, false);
@@ -1533,6 +1520,7 @@ public class GraphHopperIT {
         hopper.importOrLoad();
 
         GHRequest req = new GHRequest(55.815670, 37.604613, 55.806151, 37.617823);
+        req.setProfile("car");
         req.getHints().putObject(CH.DISABLE, false).putObject(Landmark.DISABLE, true);
         PathWrapper pathCH = hopper.route(req).getBest();
         req.getHints().putObject(CH.DISABLE, true).putObject(Landmark.DISABLE, false);
@@ -1551,23 +1539,30 @@ public class GraphHopperIT {
 
     @Test
     public void testTurnCostsOnOff() {
+        final String profile1 = "profile_no_turn_costs";
+        final String profile2 = "profile_turn_costs";
+        final String vehicle = "car";
+        final String weighting = "fastest";
         GraphHopper hopper = createGraphHopper("car|turn_costs=true").
                 setOSMFile(MOSCOW).
+                setProfiles(
+                        new ProfileConfig(profile1).setVehicle(vehicle).setWeighting(weighting).setTurnCosts(false),
+                        new ProfileConfig(profile2).setVehicle(vehicle).setWeighting(weighting).setTurnCosts(true)
+                ).
                 setStoreOnFlush(true);
         hopper.importOrLoad();
 
-        // no edge_based parameter -> use edge-based (since encoder supports it and no CH)
-        assertMoscowEdgeBased(hopper, "none", false);
-        // edge_based=false -> use node-based
-        assertMoscowNodeBased(hopper, "false", false);
-        // edge_based=true -> use edge-based
-        assertMoscowEdgeBased(hopper, "true", false);
+        GHRequest req = new GHRequest(55.813357, 37.5958585, 55.811042, 37.594689);
+        req.setProfile("profile_no_turn_costs");
+        assertEquals(400, hopper.route(req).getBest().getDistance(), 1);
+        req.setProfile("profile_turn_costs");
+        assertEquals(1044, hopper.route(req).getBest().getDistance(), 1);
     }
 
     @Test
     public void testTurnCostsOnOffCH() {
-        final String profile1 = "my_profile1";
-        final String profile2 = "my_profile2";
+        final String profile1 = "profile_turn_costs";
+        final String profile2 = "profile_no_turn_costs";
         final String vehicle = "car";
         final String weighting = "fastest";
         GraphHopper hopper = createGraphHopper("car|turn_costs=true").
@@ -1584,12 +1579,11 @@ public class GraphHopperIT {
         hopper.getCHPreparationHandler().setDisablingAllowed(true);
         hopper.importOrLoad();
 
-        // no edge_based parameter -> use edge-based (because its there)
-        assertMoscowEdgeBased(hopper, "none", true);
-        // edge_based=false -> use node-based
-        assertMoscowNodeBased(hopper, "false", true);
-        // edge_based=true -> use edge-based
-        assertMoscowEdgeBased(hopper, "true", true);
+        GHRequest req = new GHRequest(55.813357, 37.5958585, 55.811042, 37.594689);
+        req.setProfile("profile_no_turn_costs");
+        assertEquals(400, hopper.route(req).getBest().getDistance(), 1);
+        req.setProfile("profile_turn_costs");
+        assertEquals(1044, hopper.route(req).getBest().getDistance(), 1);
     }
 
     @Test
@@ -1608,10 +1602,16 @@ public class GraphHopperIT {
                 .setDisablingAllowed(true);
         hopper.importOrLoad();
 
-        // with CH -> edge-based
-        GHResponse rsp1 = assertMoscowEdgeBased(hopper, "true", false);
-        // without CH -> also edge-based
-        GHResponse rsp2 = assertMoscowEdgeBased(hopper, "true", true);
+        GHRequest req = new GHRequest(55.813357, 37.5958585, 55.811042, 37.594689);
+        req.setProfile("my_car");
+        // with CH
+        req.putHint(CH.DISABLE, true);
+        GHResponse rsp1 = hopper.route(req);
+        assertEquals(1044, rsp1.getBest().getDistance(), 1);
+        // without CH
+        req.putHint(CH.DISABLE, false);
+        GHResponse rsp2 = hopper.route(req);
+        assertEquals(1044, rsp2.getBest().getDistance(), 1);
         // just a quick check that we did not run the same algorithm twice
         assertNotEquals(rsp1.getHints().getInt("visited_nodes.sum", -1), rsp2.getHints().getInt("visited_nodes.sum", -1));
     }
@@ -1634,100 +1634,43 @@ public class GraphHopperIT {
                 .setDisablingAllowed(true);
         hopper.importOrLoad();
 
-        // without CH -> use edge-based unless disabled explicitly
-        assertMoscowEdgeBased(hopper, "none", false);
-        assertMoscowEdgeBased(hopper, "true", false);
-        assertMoscowNodeBased(hopper, "false", false);
+        GHRequest req = new GHRequest(55.813357, 37.5958585, 55.811042, 37.594689);
+        // without CH, turn turn costs on and off
+        req.putHint(CH.DISABLE, true);
+        req.setProfile(profile1);
+        assertEquals(1044, hopper.route(req).getBest().getDistance(), 1);
+        req.setProfile(profile2);
+        assertEquals(400, hopper.route(req).getBest().getDistance(), 1);
 
-        // with CH -> use node-based unless edge_based is enabled explicitly (which should give an error)
-        assertMoscowNodeBased(hopper, "none", true);
-        assertMoscowNodeBased(hopper, "false", true);
-        GHResponse rsp = runMoscow(hopper, "true", true);
+        // with CH, turn turn costs on and off, since turn costs not supported for CH throw an error
+        req.putHint(CH.DISABLE, false);
+        req.setProfile(profile2);
+        assertEquals(400, hopper.route(req).getBest().getDistance(), 1);
+        req.setProfile(profile1);
+        GHResponse rsp = hopper.route(req);
         assertEquals(1, rsp.getErrors().size());
-        String expected = "Cannot find matching CH profile for your request. Please check your parameters." +
+        String expected = "Cannot find CH preparation for the requested profile: 'car_profile_tc'" +
                 "\nYou can try disabling CH using ch.disable=true" +
-                "\nrequested:  fastest|car|edge_based=true|u_turn_costs=*\navailable: [fastest|car|edge_based=false]";
+                "\navailable CH profiles: [car_profile_notc]";
         assertTrue("unexpected error:\n" + rsp.getErrors().toString() + "\nwhen expecting an error containing:\n" + expected,
                 rsp.getErrors().toString().contains(expected));
     }
 
-    @Test
-    public void testEdgeBasedByDefaultIfOnlyEdgeBased() {
-        // when there is only one edge-based CH profile, there is no need to specify edge_based=true explicitly,
-        // see #1637
-        final String weighting = "fastest";
-        GraphHopper hopper = createGraphHopper("car|turn_costs=true").
-                setOSMFile(MOSCOW).
-                setProfiles(new ProfileConfig("profile").setVehicle("car").setWeighting(weighting).setTurnCosts(true)).
-                setStoreOnFlush(true);
-        hopper.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig("profile"));
-        hopper.getCHPreparationHandler().setDisablingAllowed(true);
-        hopper.importOrLoad();
-
-        // even when we omit the edge_based parameter we get edge-based CH, unless we disable it explicitly
-        assertMoscowEdgeBased(hopper, "none", true);
-        assertMoscowEdgeBased(hopper, "true", true);
-        GHResponse rsp = runMoscow(hopper, "false", true);
-        assertTrue(rsp.hasErrors());
-        assertTrue("unexpected error: " + rsp.getErrors(), rsp.getErrors().toString().contains(
-                "Cannot find matching CH profile for your request. Please check your parameters." +
-                        "\nYou can try disabling CH using ch.disable=true" +
-                        "\nrequested:  fastest|car|edge_based=false|u_turn_costs=*\navailable: [fastest|car|edge_based=true|u_turn_costs=-1]"));
-    }
-
-    private GHResponse assertMoscowNodeBased(GraphHopper hopper, String edgeBasedParam, boolean ch) {
-        GHResponse rsp = runMoscow(hopper, edgeBasedParam, ch);
-        assertEquals(400, rsp.getBest().getDistance(), 1);
-        return rsp;
-    }
-
-    private GHResponse assertMoscowEdgeBased(GraphHopper hopper, String edgeBasedParam, boolean ch) {
-        GHResponse rsp = runMoscow(hopper, edgeBasedParam, ch);
-        assertEquals(1044, rsp.getBest().getDistance(), 1);
-        return rsp;
-    }
-
-    private GHResponse runMoscow(GraphHopper hopper, String edgeBasedParam, boolean ch) {
-        GHRequest req = new GHRequest(55.813357, 37.5958585, 55.811042, 37.594689);
-        if (edgeBasedParam.equals("true") || edgeBasedParam.equals("false")) {
-            req.getHints().putObject(Routing.EDGE_BASED, Helper.toObject(edgeBasedParam));
-        } else {
-            req.getHints().remove(Routing.EDGE_BASED);
-        }
-        req.putHint(CH.DISABLE, !ch);
-        req.setVehicle("car");
-        req.setWeighting("fastest");
-        return hopper.route(req);
-    }
-
-    @Test
-    public void testEdgeBasedRequiresTurnCostSupport() {
-        String vehicle = "foot";
-        GraphHopper hopper = createGraphHopper(vehicle).
-                setOSMFile(MONACO).
-                setStoreOnFlush(true).
-                importOrLoad();
-        GHPoint p = new GHPoint(43.727687, 7.418737);
-        GHPoint q = new GHPoint(43.74958, 7.436566);
-        GHRequest req = new GHRequest(p, q);
-        req.putHint(Routing.EDGE_BASED, true);
-        req.setVehicle(vehicle);
-        GHResponse rsp = hopper.route(req);
-        assertTrue(rsp.hasErrors());
-        assertTrue("using edge-based for encoder without turncost support should be an error, but got:\n" + rsp.getErrors(),
-                rsp.getErrors().toString().contains("You need to set up a turn cost storage to make use of edge_based=true, e.g. use car|turn_costs=true"));
-    }
-
     @Test
     public void testEncoderWithTurnCostSupport_stillAllows_nodeBasedRouting() {
         // see #1698
+        final String profile = "profile";
+        final String vehicle = "foot";
+        final String weighting = "fastest";
         GraphHopper hopper = createGraphHopper("foot,car|turn_costs=true").
-                setOSMFile(MOSCOW);
+                setOSMFile(MOSCOW).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting));
+
         hopper.importOrLoad();
         GHPoint p = new GHPoint(55.813357, 37.5958585);
         GHPoint q = new GHPoint(55.811042, 37.594689);
         GHRequest req = new GHRequest(p, q);
-        req.setVehicle("foot");
+        req.setProfile(profile);
         GHResponse rsp = hopper.route(req);
         assertEquals("there should not be an error, but was: " + rsp.getErrors(), 0, rsp.getErrors().size());
     }
@@ -1842,14 +1785,14 @@ public class GraphHopperIT {
 
     private GHResponse calcCurbsidePath(GraphHopper hopper, GHPoint source, GHPoint target, List<String> curbsides, boolean force) {
         GHRequest req = new GHRequest(source, target);
-        req.putHint(Routing.EDGE_BASED, true);
         req.putHint(Routing.FORCE_CURBSIDE, force);
+        req.setProfile("my_profile");
         req.setCurbsides(curbsides);
         return hopper.route(req);
     }
 
     @Test
-    public void testCHWithFiniteUTurnCostsAndMissingWeighting() {
+    public void testCHWithFiniteUTurnCosts() {
         GraphHopper h = createGraphHopper("car|turn_costs=true").
                 setOSMFile(MONACO).
                 setProfiles(Collections.singletonList(
@@ -1864,8 +1807,7 @@ public class GraphHopperIT {
         GHPoint p = new GHPoint(43.73397, 7.414173);
         GHPoint q = new GHPoint(43.73222, 7.415557);
         GHRequest req = new GHRequest(p, q);
-        // note that we do *not* set the weighting on the request, it will be determined automatically from the
-        // CH profile, see #1788
+        req.setProfile("my_profile");
         // we force the start/target directions such that there are u-turns right after we start and right before
         // we reach the target
         req.setCurbsides(Arrays.asList("right", "right"));
@@ -1878,8 +1820,10 @@ public class GraphHopperIT {
 
     @Test
     public void simplifyWithInstructionsAndPathDetails() {
+        final String profile = "profile";
         GraphHopper hopper = new GraphHopperOSM().
                 setOSMFile(BAYREUTH).
+                setProfiles(new ProfileConfig(profile).setVehicle("car").setWeighting("fastest")).
                 setGraphHopperLocation(GH_LOCATION).
                 forServer();
         EncodingManager em = new EncodingManager.Builder()
@@ -1894,6 +1838,7 @@ public class GraphHopperIT {
                 .addPoint(new GHPoint(50.026932, 11.493201))
                 .addPoint(new GHPoint(50.016895, 11.4923))
                 .addPoint(new GHPoint(50.003464, 11.49157))
+                .setProfile(profile)
                 .setPathDetails(Arrays.asList("street_name", "max_speed"));
         req.putHint("elevation", true);
 
diff --git a/reader-osm/src/test/java/com/graphhopper/reader/osm/GraphHopperOSMTest.java b/reader-osm/src/test/java/com/graphhopper/reader/osm/GraphHopperOSMTest.java
index ef679c90d..e1851ddd7 100644
--- a/reader-osm/src/test/java/com/graphhopper/reader/osm/GraphHopperOSMTest.java
+++ b/reader-osm/src/test/java/com/graphhopper/reader/osm/GraphHopperOSMTest.java
@@ -80,17 +80,18 @@ public class GraphHopperOSMTest {
 
     @Test
     public void testLoadOSM() {
+        String profile = "car_profile";
         String vehicle = "car";
         String weighting = "fastest";
         GraphHopper hopper = createGraphHopper(vehicle).
                 setStoreOnFlush(true).
-                setProfiles(new ProfileConfig("car_profile").setVehicle(vehicle).setWeighting(weighting)).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setGraphHopperLocation(ghLoc).
                 setDataReaderFile(testOsm);
-        hopper.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig("car_profile"));
+        hopper.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig(profile));
         hopper.importOrLoad();
         GHResponse rsp = hopper.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4).
-                setVehicle(vehicle).setWeighting(weighting));
+                setProfile(profile));
         assertFalse(rsp.hasErrors());
         assertEquals(3, rsp.getBest().getPoints().getSize());
 
@@ -98,19 +99,19 @@ public class GraphHopperOSMTest {
 
         // no encoding manager necessary
         hopper = new GraphHopperOSM().
-                setProfiles(new ProfileConfig("car_profile").setVehicle(vehicle).setWeighting(weighting)).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true);
-        hopper.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig("car_profile"));
+        hopper.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig(profile));
         assertTrue(hopper.load(ghLoc));
         rsp = hopper.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4).
-                setVehicle(vehicle).setWeighting(weighting));
+                setProfile(profile));
         assertFalse(rsp.hasErrors());
         assertEquals(3, rsp.getBest().getPoints().getSize());
 
         hopper.close();
         try {
             rsp = hopper.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4)
-                    .setVehicle(vehicle).setWeighting(weighting));
+                    .setProfile(profile));
             fail();
         } catch (Exception ex) {
             assertEquals("You need to create a new GraphHopper instance as it is already closed", ex.getMessage());
@@ -126,9 +127,11 @@ public class GraphHopperOSMTest {
 
     @Test
     public void testLoadOSMNoCH() {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "fastest";
         GraphHopper gh = createGraphHopper(vehicle).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true).
                 setGraphHopperLocation(ghLoc).
                 setDataReaderFile(testOsm);
@@ -137,22 +140,24 @@ public class GraphHopperOSMTest {
         assertFalse(gh.getAlgorithmFactory("profile", false, false) instanceof CHRoutingAlgorithmFactory);
 
         GHResponse rsp = gh.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4)
-                .setVehicle(vehicle).setWeighting(weighting));
+                .setProfile(profile));
         assertFalse(rsp.hasErrors());
         assertEquals(3, rsp.getBest().getPoints().getSize());
 
         gh.close();
         gh = createGraphHopper(vehicle).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true);
         assertTrue(gh.load(ghLoc));
         rsp = gh.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4)
-                .setVehicle(vehicle).setWeighting(weighting));
+                .setProfile(profile));
         assertFalse(rsp.hasErrors());
         assertEquals(3, rsp.getBest().getPoints().getSize());
 
         gh.close();
 
         gh = createGraphHopper(vehicle).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setGraphHopperLocation(ghLoc).
                 setDataReaderFile(testOsm);
 
@@ -222,16 +227,17 @@ public class GraphHopperOSMTest {
     public void testLoadingWithDifferentCHConfig_issue471_pr1488() {
         // when there is a single CH profile we can also load GraphHopper without it
         // in #471 this was forbidden, but later it was allowed again, see #1488
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "fastest";
         GraphHopper gh = createGraphHopper(vehicle).
                 setStoreOnFlush(true).
-                setProfiles(Collections.singletonList(new ProfileConfig("profile").setVehicle(vehicle).setWeighting(weighting))).
+                setProfiles(Collections.singletonList(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting))).
                 setGraphHopperLocation(ghLoc).
                 setDataReaderFile(testOsm);
-        gh.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig("profile"));
+        gh.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig(profile));
         gh.importOrLoad();
-        GHResponse rsp = gh.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4));
+        GHResponse rsp = gh.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4).setProfile(profile));
         assertFalse(rsp.hasErrors());
         assertEquals(3, rsp.getBest().getPoints().getSize());
         gh.close();
@@ -247,16 +253,17 @@ public class GraphHopperOSMTest {
         // when there is no CH preparation we get an error if we try to load GH with a CH profile
         gh = createGraphHopper(vehicle).
                 setStoreOnFlush(true).
+                setProfiles(Collections.singletonList(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting))).
                 setGraphHopperLocation(ghLoc).
                 setDataReaderFile(testOsm);
         gh.importOrLoad();
-        rsp = gh.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4));
+        rsp = gh.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4).setProfile(profile));
         assertFalse(rsp.hasErrors());
         assertEquals(3, rsp.getBest().getPoints().getSize());
         gh.close();
 
         gh = createGraphHopper("car").
-                setProfiles(new ProfileConfig("profile").setVehicle(vehicle).setWeighting(weighting)).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true);
         gh.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig("profile"));
 
@@ -310,6 +317,7 @@ public class GraphHopperOSMTest {
         }.setStoreOnFlush(true).
                 setEncodingManager(EncodingManager.create("car")).
                 setGraphHopperLocation(ghLoc).
+                setProfiles(new ProfileConfig("car").setVehicle("car").setWeighting("fastest")).
                 setDataReaderFile(testOsm);
         final AtomicReference<Exception> ar = new AtomicReference<>();
         Thread thread = new Thread() {
@@ -332,7 +340,7 @@ public class GraphHopperOSMTest {
             latch2.await(3, TimeUnit.SECONDS);
             // now importOrLoad should have create a lock which this load call does not like
             instance2.load(ghLoc);
-            fail();
+            fail("There should have been an error because of the lock");
         } catch (RuntimeException ex) {
             assertNotNull(ex);
             assertTrue(ex.getMessage(), ex.getMessage().startsWith("To avoid reading partial data"));
@@ -350,18 +358,19 @@ public class GraphHopperOSMTest {
 
     @Test
     public void testPrepare() {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "shortest";
 
         instance = createGraphHopper(vehicle).
                 setStoreOnFlush(false).
-                setProfiles(Collections.singletonList(new ProfileConfig("profile").setVehicle(vehicle).setWeighting(weighting))).
+                setProfiles(Collections.singletonList(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting))).
                 setGraphHopperLocation(ghLoc).
                 setDataReaderFile(testOsm);
-        instance.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig("profile"));
+        instance.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig(profile));
         instance.importOrLoad();
         GHResponse rsp = instance.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4).
-                setVehicle(vehicle).setWeighting(weighting).
+                setProfile(profile).
                 setAlgorithm(DIJKSTRA_BI));
         assertFalse(rsp.hasErrors());
         assertEquals(Helper.createPointList(51.249215, 9.431716, 52.0, 9.0, 51.2, 9.4), rsp.getBest().getPoints());
@@ -370,16 +379,18 @@ public class GraphHopperOSMTest {
 
     @Test
     public void testSortedGraph_noCH() {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "fastest";
         instance = createGraphHopper(vehicle).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(false).
                 setSortGraph(true).
                 setGraphHopperLocation(ghLoc).
                 setDataReaderFile(testOsm);
         instance.importOrLoad();
         PathWrapper rsp = instance.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4).
-                setVehicle(vehicle).setWeighting(weighting).
+                setProfile(profile).
                 setAlgorithm(DIJKSTRA_BI)).getBest();
         assertFalse(rsp.hasErrors());
         assertEquals(3, rsp.getPoints().getSize());
@@ -388,7 +399,7 @@ public class GraphHopperOSMTest {
         assertEquals(new GHPoint(51.199999850988384, 9.39999970197677), rsp.getPoints().get(2));
 
         GHRequest req = new GHRequest(51.2492152, 9.4317166, 51.2, 9.4);
-        req.setVehicle(vehicle).setWeighting(weighting);
+        req.setProfile(profile);
         boolean old = instance.getEncodingManager().isEnableInstructions();
         req.putHint("instructions", true);
         instance.route(req);
@@ -401,12 +412,18 @@ public class GraphHopperOSMTest {
 
     @Test
     public void testFootAndCar() {
+        final String profile1 = "profile1";
+        final String profile2 = "profile2";
         final String vehicle1 = "car";
         final String vehicle2 = "foot";
         final String weighting = "fastest";
 
         // now all ways are imported
         instance = createGraphHopper(vehicle1 + "," + vehicle2).
+                setProfiles(
+                        new ProfileConfig(profile1).setVehicle(vehicle1).setWeighting(weighting),
+                        new ProfileConfig(profile2).setVehicle(vehicle2).setWeighting(weighting)
+                ).
                 setStoreOnFlush(false).
                 setGraphHopperLocation(ghLoc).
                 setDataReaderFile(testOsm3);
@@ -416,7 +433,7 @@ public class GraphHopperOSMTest {
         assertEquals(8, instance.getGraphHopperStorage().getEdges());
 
         // A to D
-        GHResponse grsp = instance.route(new GHRequest(11.1, 50, 11.3, 51).setVehicle(vehicle1).setWeighting(weighting));
+        GHResponse grsp = instance.route(new GHRequest(11.1, 50, 11.3, 51).setProfile(profile1));
         assertFalse(grsp.hasErrors());
         PathWrapper rsp = grsp.getBest();
         assertEquals(3, rsp.getPoints().getSize());
@@ -427,7 +444,7 @@ public class GraphHopperOSMTest {
         assertEquals(11.3, rsp.getPoints().getLatitude(2), 1e-3);
 
         // A to D not allowed for foot. But the location index will choose a node close to D accessible to FOOT
-        grsp = instance.route(new GHRequest(11.1, 50, 11.3, 51).setVehicle(vehicle2).setWeighting(weighting));
+        grsp = instance.route(new GHRequest(11.1, 50, 11.3, 51).setProfile(profile2));
         assertFalse(grsp.hasErrors());
         rsp = grsp.getBest();
         assertEquals(2, rsp.getPoints().getSize());
@@ -436,13 +453,13 @@ public class GraphHopperOSMTest {
         assertEquals(50.644, rsp.getPoints().getLongitude(1), 1e-3);
 
         // A to E only for foot
-        grsp = instance.route(new GHRequest(11.1, 50, 10, 51).setVehicle(vehicle2).setWeighting(weighting));
+        grsp = instance.route(new GHRequest(11.1, 50, 10, 51).setProfile(profile2));
         assertFalse(grsp.hasErrors());
         rsp = grsp.getBest();
         assertEquals(2, rsp.getPoints().size());
 
         // A D E for car
-        grsp = instance.route(new GHRequest(11.1, 50, 10, 51).setVehicle(vehicle1).setWeighting(weighting));
+        grsp = instance.route(new GHRequest(11.1, 50, 10, 51).setProfile(profile1));
         assertFalse(grsp.hasErrors());
         rsp = grsp.getBest();
         assertEquals(3, rsp.getPoints().getSize());
@@ -455,7 +472,11 @@ public class GraphHopperOSMTest {
                         putObject("datareader.file", testOsm3).
                         putObject("datareader.dataaccess", "RAM").
                         putObject("graph.flag_encoders", "foot,car")).
-                setGraphHopperLocation(ghLoc);
+                setGraphHopperLocation(ghLoc).
+                setProfiles(Arrays.asList(
+                        new ProfileConfig("foot").setVehicle("foot").setWeighting("fastest"),
+                        new ProfileConfig("car").setVehicle("car").setWeighting("fastest")
+                ));
         instance.importOrLoad();
         assertEquals(5, instance.getGraphHopperStorage().getNodes());
         instance.close();
@@ -467,7 +488,10 @@ public class GraphHopperOSMTest {
                             putObject("datareader.file", testOsm3).
                             putObject("datareader.dataaccess", "RAM").
                             putObject("graph.flag_encoders", "foot")).
-                    setDataReaderFile(testOsm3);
+                    setDataReaderFile(testOsm3).
+                    setProfiles(Collections.singletonList(
+                            new ProfileConfig("foot").setVehicle("foot").setWeighting("fastest")
+                    ));
             tmpGH.load(ghLoc);
             fail();
         } catch (Exception ex) {
@@ -480,7 +504,11 @@ public class GraphHopperOSMTest {
                     putObject("datareader.file", testOsm3).
                     putObject("datareader.dataaccess", "RAM").
                     putObject("graph.flag_encoders", "car,foot")).
-                    setDataReaderFile(testOsm3);
+                    setDataReaderFile(testOsm3).
+                    setProfiles(Arrays.asList(
+                            new ProfileConfig("car").setVehicle("car").setWeighting("fastest"),
+                            new ProfileConfig("foot").setVehicle("foot").setWeighting("fastest")
+                    ));
             tmpGH.load(ghLoc);
             fail();
         } catch (Exception ex) {
@@ -494,7 +522,11 @@ public class GraphHopperOSMTest {
                         putObject("datareader.dataaccess", "RAM").
                         putObject("graph.encoded_values", "road_class").
                         putObject("graph.flag_encoders", "foot,car")).
-                setDataReaderFile(testOsm3);
+                setDataReaderFile(testOsm3).
+                setProfiles(Arrays.asList(
+                        new ProfileConfig("foot").setVehicle("foot").setWeighting("fastest"),
+                        new ProfileConfig("car").setVehicle("car").setWeighting("fastest")
+                ));
         try {
             instance.load(ghLoc);
             fail();
@@ -511,7 +543,10 @@ public class GraphHopperOSMTest {
         })).init(new GraphHopperConfig().
                 putObject("datareader.file", testOsm3).
                 putObject("datareader.dataaccess", "RAM")).
-                setDataReaderFile(testOsm3);
+                setDataReaderFile(testOsm3).
+                setProfiles(Collections.singletonList(
+                        new ProfileConfig("car").setVehicle("car").setWeighting("fastest")
+                ));
         try {
             instance.load(ghLoc);
             fail();
@@ -527,6 +562,10 @@ public class GraphHopperOSMTest {
                         putObject("datareader.file", testOsm3).
                         putObject("datareader.dataaccess", "RAM").
                         putObject("graph.flag_encoders", "foot,car")).
+                setProfiles(Arrays.asList(
+                        new ProfileConfig("foot").setVehicle("foot").setWeighting("fastest"),
+                        new ProfileConfig("car").setVehicle("car").setWeighting("fastest")
+                )).
                 setGraphHopperLocation(ghLoc);
         instance.importOrLoad();
         // older versions <= 0.12 did not store this property, ensure that we fail to load it
@@ -542,6 +581,10 @@ public class GraphHopperOSMTest {
                         putObject("datareader.dataaccess", "RAM").
                         putObject("graph.encoded_values", "road_environment,road_class").
                         putObject("graph.flag_encoders", "foot,car")).
+                setProfiles(Arrays.asList(
+                        new ProfileConfig("foot").setVehicle("foot").setWeighting("fastest"),
+                        new ProfileConfig("car").setVehicle("car").setWeighting("fastest")
+                )).
                 setDataReaderFile(testOsm3);
         try {
             instance.load(ghLoc);
@@ -553,13 +596,17 @@ public class GraphHopperOSMTest {
 
     @Test
     public void testNoNPE_ifLoadNotSuccessful() {
-        instance = createGraphHopper("car").
+        String profile = "profile";
+        String vehicle = "car";
+        String weighting = "fastest";
+        instance = createGraphHopper(vehicle).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setStoreOnFlush(true);
         try {
             // loading from empty directory
             new File(ghLoc).mkdirs();
             assertFalse(instance.load(ghLoc));
-            instance.route(new GHRequest(10, 40, 12, 32));
+            instance.route(new GHRequest(10, 40, 12, 32).setProfile(profile));
             fail();
         } catch (IllegalStateException ex) {
             assertEquals("Do a successful call to load or importOrLoad before routing", ex.getMessage());
@@ -641,21 +688,22 @@ public class GraphHopperOSMTest {
     @Test
     public void testFootOnly() {
         // now only footable ways are imported => no A D C and B D E => the other both ways have pillar nodes!
+        final String profile = "foot_profile";
         final String vehicle = "foot";
         final String weighting = "fastest";
         instance = createGraphHopper(vehicle).
                 setStoreOnFlush(false).
-                setProfiles(new ProfileConfig("foot_profile").setVehicle(vehicle).setWeighting(weighting)).
+                setProfiles(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)).
                 setGraphHopperLocation(ghLoc).
                 setDataReaderFile(testOsm3);
-        instance.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig("foot_profile"));
+        instance.getCHPreparationHandler().setCHProfileConfigs(new CHProfileConfig(profile));
         instance.importOrLoad();
 
         assertEquals(2, instance.getGraphHopperStorage().getNodes());
         assertEquals(2, instance.getGraphHopperStorage().getAllEdges().length());
 
         // A to E only for foot
-        GHResponse grsp = instance.route(new GHRequest(11.1, 50, 11.19, 52).setVehicle(vehicle).setWeighting(weighting));
+        GHResponse grsp = instance.route(new GHRequest(11.1, 50, 11.19, 52).setProfile(profile));
         assertFalse(grsp.hasErrors());
         PathWrapper rsp = grsp.getBest();
         // the last points snaps to the edge
@@ -664,6 +712,7 @@ public class GraphHopperOSMTest {
 
     @Test
     public void testVia() {
+        final String profile = "profile";
         final String vehicle = "car";
         final String weighting = "fastest";
         instance = new GraphHopperOSM().setStoreOnFlush(true).
@@ -671,8 +720,8 @@ public class GraphHopperOSMTest {
                         putObject("datareader.file", testOsm3).
                         putObject("prepare.min_network_size", 1).
                         putObject("graph.flag_encoders", vehicle)
-                        .setProfiles(Collections.singletonList(new ProfileConfig("profile").setVehicle(vehicle).setWeighting(weighting)))
-                        .setCHProfiles(Collections.singletonList(new CHProfileConfig("profile")))
+                        .setProfiles(Collections.singletonList(new ProfileConfig(profile).setVehicle(vehicle).setWeighting(weighting)))
+                        .setCHProfiles(Collections.singletonList(new CHProfileConfig(profile)))
                 ).
                 setGraphHopperLocation(ghLoc);
         instance.importOrLoad();
@@ -681,14 +730,14 @@ public class GraphHopperOSMTest {
         GHPoint first = new GHPoint(11.1, 50);
         GHPoint second = new GHPoint(12, 51);
         GHPoint third = new GHPoint(11.2, 51.9);
-        GHResponse rsp12 = instance.route(new GHRequest().addPoint(first).addPoint(second).setVehicle(vehicle).setWeighting(weighting));
+        GHResponse rsp12 = instance.route(new GHRequest().addPoint(first).addPoint(second).setProfile(profile));
         assertFalse("should find 1->2", rsp12.hasErrors());
         assertEquals(147930.5, rsp12.getBest().getDistance(), .1);
-        GHResponse rsp23 = instance.route(new GHRequest().addPoint(second).addPoint(third).setVehicle(vehicle).setWeighting(weighting));
+        GHResponse rsp23 = instance.route(new GHRequest().addPoint(second).addPoint(third).setProfile(profile));
         assertFalse("should find 2->3", rsp23.hasErrors());
         assertEquals(176608.9, rsp23.getBest().getDistance(), .1);
 
-        GHResponse grsp = instance.route(new GHRequest().addPoint(first).addPoint(second).addPoint(third).setVehicle(vehicle).setWeighting(weighting));
+        GHResponse grsp = instance.route(new GHRequest().addPoint(first).addPoint(second).addPoint(third).setProfile(profile));
         assertFalse("should find 1->2->3", grsp.hasErrors());
         PathWrapper rsp = grsp.getBest();
         assertEquals(rsp12.getBest().getDistance() + rsp23.getBest().getDistance(), rsp.getDistance(), 1e-6);
@@ -708,7 +757,7 @@ public class GraphHopperOSMTest {
         // End at middle of edge 2-3
         GHPoint end = new GHPoint(0.002, 0.0005);
 
-        GHRequest req = new GHRequest().addPoint(start, 180.).addPoint(end).setVehicle("car").setWeighting("fastest");
+        GHRequest req = new GHRequest().addPoint(start, 180.).addPoint(end).setProfile("profile");
         GHResponse response = new GHResponse();
         List<Path> paths = instance.calcPaths(req, response);
         assertFalse(response.hasErrors());
@@ -725,7 +774,7 @@ public class GraphHopperOSMTest {
         // End at middle of edge 2-3
         GHPoint end = new GHPoint(0.002, 0.0005);
 
-        GHRequest req = new GHRequest().addPoint(start, 180.).addPoint(end, 90.).setVehicle("car").setWeighting("fastest");
+        GHRequest req = new GHRequest().addPoint(start, 180.).addPoint(end, 90.).setProfile("profile");
         GHResponse response = new GHResponse();
         List<Path> paths = instance.calcPaths(req, response);
         assertFalse(response.hasErrors());
@@ -735,7 +784,7 @@ public class GraphHopperOSMTest {
         req.setAlgorithm(DIJKSTRA);
         response = new GHResponse();
         paths = instance.calcPaths(req, response);
-        assertFalse(response.hasErrors());
+        assertFalse(response.getErrors().toString(), response.hasErrors());
         assertArrayEquals(new int[]{9, 5, 8, 1, 2, 10}, paths.get(0).calcNodes().toArray());
     }
 
@@ -750,7 +799,7 @@ public class GraphHopperOSMTest {
         // Via Point betweeen 8-7
         GHPoint via = new GHPoint(0.0005, 0.001);
 
-        GHRequest req = new GHRequest().addPoint(start).addPoint(via, 0.).addPoint(end).setVehicle("car").setWeighting("fastest");
+        GHRequest req = new GHRequest().addPoint(start).addPoint(via, 0.).addPoint(end).setProfile("profile");
         GHResponse response = new GHResponse();
         List<Path> paths = instance.calcPaths(req, response);
         assertFalse(response.hasErrors());
@@ -768,7 +817,7 @@ public class GraphHopperOSMTest {
         GHPoint end = new GHPoint(0.002, 0.0005);
         // Via Point betweeen 8-3
         GHPoint via = new GHPoint(0.0015, 0.001);
-        GHRequest req = new GHRequest().addPoint(start).addPoint(via).addPoint(end).setVehicle("car").setWeighting("fastest");
+        GHRequest req = new GHRequest().addPoint(start).addPoint(via).addPoint(end).setProfile("profile");
         req.putHint(Routing.PASS_THROUGH, true);
         GHResponse response = new GHResponse();
         List<Path> paths = instance.calcPaths(req, response);
@@ -789,7 +838,7 @@ public class GraphHopperOSMTest {
         GHPoint end = new GHPoint(0.002, 0.0005);
         // First go south and than come from west to via-point at 7-6. Then go back over previously punished (11)-4 edge
         GHPoint via = new GHPoint(0.000, 0.0015);
-        GHRequest req = new GHRequest().addPoint(start, 0.).addPoint(via, 3.14 / 2).addPoint(end).setVehicle("car").setWeighting("fastest");
+        GHRequest req = new GHRequest().addPoint(start, 0.).addPoint(via, 3.14 / 2).addPoint(end).setProfile("profile");
         req.putHint(Routing.PASS_THROUGH, true);
         GHResponse response = new GHResponse();
         List<Path> paths = instance.calcPaths(req, response);
@@ -808,7 +857,7 @@ public class GraphHopperOSMTest {
         GHPoint via = new GHPoint(0.002, 0.000);
         GHPoint end = new GHPoint(0.002, 0.002);
 
-        GHRequest req = new GHRequest().addPoint(start, 90.).addPoint(via, 270.).addPoint(end, 270.).setVehicle("car").setWeighting("fastest");
+        GHRequest req = new GHRequest().addPoint(start, 90.).addPoint(via, 270.).addPoint(end, 270.).setProfile("profile");
         GHResponse response = new GHResponse();
         List<Path> paths = instance.calcPaths(req, response);
         assertFalse(response.hasErrors());
@@ -853,7 +902,8 @@ public class GraphHopperOSMTest {
         g.edge(7, 8, 110, true);
 
         GraphHopper tmp = new GraphHopperOSM().
-                setEncodingManager(encodingManager);
+                setEncodingManager(encodingManager).
+                setProfiles(new ProfileConfig("profile").setVehicle("car").setWeighting("fastest"));
         tmp.setGraphHopperStorage(g);
         tmp.postProcessing();
 
@@ -1032,8 +1082,14 @@ public class GraphHopperOSMTest {
     }
 
     private GraphHopper createGraphHopper(String vehicles) {
+        EncodingManager em = EncodingManager.create(vehicles);
+        List<ProfileConfig> profiles = new ArrayList<>();
+        for (FlagEncoder enc : em.fetchEdgeEncoders()) {
+            profiles.add(new ProfileConfig(enc.toString()).setVehicle(enc.toString()).setWeighting("fastest"));
+        }
         return new GraphHopperOSM().
-                setEncodingManager(EncodingManager.create(vehicles));
+                setEncodingManager(em).
+                setProfiles(profiles);
     }
 
     private static class TestEncoder extends CarFlagEncoder {
diff --git a/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java b/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java
index 9f554397b..c9eb3601e 100644
--- a/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java
+++ b/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java
@@ -22,6 +22,7 @@ import com.graphhopper.GHRequest;
 import com.graphhopper.GHResponse;
 import com.graphhopper.GraphHopper;
 import com.graphhopper.GraphHopperIT;
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.reader.DataReader;
 import com.graphhopper.reader.ReaderNode;
 import com.graphhopper.reader.ReaderRelation;
@@ -563,6 +564,7 @@ public class OSMReaderTest {
         hopper.setEncodingManager(new EncodingManager.Builder().
                 add(new OSMMaxWidthParser()).add(new OSMMaxHeightParser()).add(new OSMMaxWeightParser()).
                 add(encoder).build());
+        hopper.setProfiles(new ProfileConfig("car").setVehicle("car").setWeighting("fastest"));
         hopper.importOrLoad();
 
         DecimalEncodedValue widthEnc = hopper.getEncodingManager().getDecimalEncodedValue(MaxWidth.KEY);
@@ -711,7 +713,13 @@ public class OSMReaderTest {
 
         GraphHopper hopper = new GraphHopperOSM().
                 setOSMFile(getClass().getResource("test-multi-profile-turn-restrictions.xml").getFile()).
-                setGraphHopperLocation(dir).setEncodingManager(manager).importOrLoad();
+                setGraphHopperLocation(dir).setEncodingManager(manager).
+                setProfiles(
+                        new ProfileConfig("bike").setVehicle("bike").setWeighting("fastest"),
+                        new ProfileConfig("car").setVehicle("car").setWeighting("fastest"),
+                        new ProfileConfig("truck").setVehicle("truck").setWeighting("fastest")
+                ).
+                importOrLoad();
 
         DecimalEncodedValue carTCEnc = manager.getDecimalEncodedValue(TurnCost.key("car"));
         DecimalEncodedValue truckTCEnc = manager.getDecimalEncodedValue(TurnCost.key("truck"));
@@ -899,11 +907,14 @@ public class OSMReaderTest {
         GraphHopper hopper = new GraphHopperOSM()
                 .setDataReaderFile(getClass().getResource(file7).getFile())
                 .setEncodingManager(EncodingManager.create("car,motorcycle"))
+                .setProfiles(
+                        new ProfileConfig("profile1").setVehicle("car").setWeighting("fastest"),
+                        new ProfileConfig("profile2").setVehicle("motorcycle").setWeighting("curvature")
+                )
                 .setGraphHopperLocation(dir);
         hopper.importOrLoad();
         GHRequest req = new GHRequest(48.977277, 8.256896, 48.978876, 8.254884).
-                setWeighting("curvature").
-                setVehicle("motorcycle");
+                setProfile("profile2");
 
         GHResponse ghRsp = hopper.route(req);
         assertFalse(ghRsp.getErrors().toString(), ghRsp.hasErrors());
@@ -924,19 +935,20 @@ public class OSMReaderTest {
                 }
             }
         }.setEncodingManager(EncodingManager.create("car,bike")).
+                setProfiles(new ProfileConfig("profile").setVehicle("car").setWeighting("fastest")).
                 setGraphHopperLocation(dir).
                 importOrLoad();
 
         GHResponse response = gh.route(new GHRequest(51.2492152, 9.4317166, 52.133, 9.1)
-                .setVehicle("car").setWeighting("fastest")
-                .setPathDetails(Arrays.asList(RoadClass.KEY)));
+                .setProfile("profile")
+                .setPathDetails(Collections.singletonList(RoadClass.KEY)));
         List<PathDetail> list = response.getBest().getPathDetails().get(RoadClass.KEY);
         assertEquals(3, list.size());
         assertEquals(RoadClass.MOTORWAY.toString(), list.get(0).getValue());
 
         response = gh.route(new GHRequest(51.2492152, 9.4317166, 52.133, 9.1)
-                .setVehicle("car").setWeighting("fastest")
-                .setPathDetails(Arrays.asList(Toll.KEY)));
+                .setProfile("profile")
+                .setPathDetails(Collections.singletonList(Toll.KEY)));
         Throwable ex = response.getErrors().get(0);
         assertTrue(ex.getMessage(), ex.getMessage().contains("You requested the details [toll]"));
     }
@@ -963,6 +975,11 @@ public class OSMReaderTest {
             footEncoder = new FootFlagEncoder();
             setEncodingManager(new EncodingManager.Builder().add(footEncoder).add(carEncoder).add(bikeEncoder).
                     setPreferredLanguage(prefLang).build());
+            setProfiles(
+                    new ProfileConfig("foot").setVehicle("foot").setWeighting("fastest"),
+                    new ProfileConfig("car").setVehicle("car").setWeighting("fastest"),
+                    new ProfileConfig("bike").setVehicle("bike").setWeighting("fastest")
+            );
             carAccessEnc = carEncoder.getAccessEnc();
         }
 
diff --git a/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMIT.java b/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMIT.java
index 8f5ee4a5f..3009fbf3c 100644
--- a/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMIT.java
+++ b/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMIT.java
@@ -37,7 +37,6 @@ import org.junit.Before;
 import org.junit.Test;
 
 import java.io.File;
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -621,7 +620,7 @@ public class RoutingAlgorithmWithOSMIT {
     }
 
     @Test
-    public void testMonacoParallel() throws IOException {
+    public void testMonacoParallel() {
         System.out.println("testMonacoParallel takes a bit time...");
         String graphFile = "target/monaco-gh";
         Helper.removeDir(new File(graphFile));
@@ -632,6 +631,7 @@ public class RoutingAlgorithmWithOSMIT {
                 setWayPointMaxDistance(0).
                 setDataReaderFile(DIR + "/monaco.osm.gz").
                 setGraphHopperLocation(graphFile).
+                setProfiles(new ProfileConfig("car").setVehicle("car").setWeighting("fastest")).
                 importOrLoad();
         final Graph g = hopper.getGraphHopperStorage();
         final LocationIndex idx = hopper.getLocationIndex();
diff --git a/web/src/test/java/com/graphhopper/http/GraphHopperLandmarksTest.java b/web/src/test/java/com/graphhopper/http/GraphHopperLandmarksTest.java
index 4a4d0550b..0a9b998de 100644
--- a/web/src/test/java/com/graphhopper/http/GraphHopperLandmarksTest.java
+++ b/web/src/test/java/com/graphhopper/http/GraphHopperLandmarksTest.java
@@ -24,16 +24,17 @@ import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
 import com.graphhopper.util.Helper;
 import io.dropwizard.testing.junit.DropwizardAppRule;
+import org.junit.AfterClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import javax.ws.rs.core.Response;
 import java.io.File;
 import java.util.Collections;
 
+import static com.graphhopper.http.util.TestUtils.clientTarget;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import org.junit.ClassRule;
-import org.junit.Test;
-import static com.graphhopper.http.util.TestUtils.clientTarget;
-import javax.ws.rs.core.Response;
-import org.junit.AfterClass;
 
 /**
  * Tests the creation of Landmarks and parsing the map.geo.json file
diff --git a/web/src/test/java/com/graphhopper/http/SpatialRulesTest.java b/web/src/test/java/com/graphhopper/http/SpatialRulesTest.java
index 91f980432..66a09f9b9 100644
--- a/web/src/test/java/com/graphhopper/http/SpatialRulesTest.java
+++ b/web/src/test/java/com/graphhopper/http/SpatialRulesTest.java
@@ -18,16 +18,20 @@
 package com.graphhopper.http;
 
 import com.fasterxml.jackson.databind.JsonNode;
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
 import com.graphhopper.util.Helper;
 import io.dropwizard.testing.junit.DropwizardAppRule;
-import java.io.File;
-import javax.ws.rs.core.Response;
 import org.junit.AfterClass;
-import static org.junit.Assert.*;
 import org.junit.ClassRule;
 import org.junit.Test;
+
+import javax.ws.rs.core.Response;
+import java.io.File;
+import java.util.Collections;
+
 import static com.graphhopper.http.util.TestUtils.clientTarget;
+import static org.junit.Assert.*;
 
 /**
  * Tests the DataFlagEncoder with the SpatialRuleLookup enabled
@@ -48,7 +52,8 @@ public class SpatialRulesTest {
                 putObject("spatial_rules.borders_directory", "../core/files/spatialrules").
                 putObject("spatial_rules.max_bbox", "11.4,11.7,49.9,50.1").
                 putObject("datareader.file", "../core/files/north-bayreuth.osm.gz").
-                putObject("graph.location", DIR);
+                putObject("graph.location", DIR).
+                setProfiles(Collections.singletonList(new ProfileConfig("profile").setVehicle("car").setWeighting("fastest")));
     }
 
     @ClassRule
diff --git a/web/src/test/java/com/graphhopper/http/resources/ChangeGraphResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/ChangeGraphResourceTest.java
index c26a17186..d26b156b2 100644
--- a/web/src/test/java/com/graphhopper/http/resources/ChangeGraphResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/ChangeGraphResourceTest.java
@@ -18,18 +18,22 @@
 package com.graphhopper.http.resources;
 
 import com.fasterxml.jackson.databind.JsonNode;
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.GraphHopperApplication;
 import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
 import com.graphhopper.util.Helper;
 import io.dropwizard.testing.junit.DropwizardAppRule;
-import java.io.File;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.Response;
 import org.junit.AfterClass;
-import static org.junit.Assert.*;
 import org.junit.ClassRule;
 import org.junit.Test;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Response;
+import java.io.File;
+import java.util.Collections;
+
 import static com.graphhopper.http.util.TestUtils.clientTarget;
+import static org.junit.Assert.*;
 
 /**
  * @author Peter Karich
@@ -44,7 +48,8 @@ public class ChangeGraphResourceTest {
                 putObject("graph.flag_encoders", "car").
                 putObject("web.change_graph.enabled", true).
                 putObject("graph.location", DIR).
-                putObject("datareader.file", "../core/files/andorra.osm.pbf");
+                putObject("datareader.file", "../core/files/andorra.osm.pbf").
+                setProfiles(Collections.singletonList(new ProfileConfig("car").setVehicle("car").setWeighting("fastest")));
     }
 
     @ClassRule
@@ -57,7 +62,7 @@ public class ChangeGraphResourceTest {
     }
 
     @Test
-    public void testBlockAccessViaPoint() throws Exception {
+    public void testBlockAccessViaPoint() {
         Response response = clientTarget(app, "route?point=42.531453,1.518946&point=42.511178,1.54006").request().buildGet().invoke();
         assertEquals(200, response.getStatus());
         JsonNode json = response.readEntity(JsonNode.class);
diff --git a/web/src/test/java/com/graphhopper/http/resources/GpxTravelTimeConsistencyTest.java b/web/src/test/java/com/graphhopper/http/resources/GpxTravelTimeConsistencyTest.java
index 8dd17caa8..0eace703f 100644
--- a/web/src/test/java/com/graphhopper/http/resources/GpxTravelTimeConsistencyTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/GpxTravelTimeConsistencyTest.java
@@ -21,6 +21,7 @@ package com.graphhopper.http.resources;
 import com.graphhopper.GHRequest;
 import com.graphhopper.GraphHopper;
 import com.graphhopper.PathWrapper;
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.reader.osm.GraphHopperOSM;
 import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.util.Helper;
@@ -40,7 +41,6 @@ public class GpxTravelTimeConsistencyTest {
     public static final String DIR = "../core/files";
     private static final String graphFileFoot = "target/gpxtraveltimeconsistency-it";
     private static final String osmFile = DIR + "/monaco.osm.gz";
-    private static final String importVehicles = "foot";
     private static GraphHopper hopper;
 
     @BeforeClass
@@ -48,9 +48,10 @@ public class GpxTravelTimeConsistencyTest {
         Helper.removeDir(new File(graphFileFoot));
         hopper = new GraphHopperOSM().
                 setOSMFile(osmFile).
+                setProfiles(new ProfileConfig("profile").setVehicle("foot").setWeighting("fastest")).
                 setStoreOnFlush(true).
                 setGraphHopperLocation(graphFileFoot).
-                setEncodingManager(EncodingManager.create(importVehicles)).
+                setEncodingManager(EncodingManager.create("foot")).
                 importOrLoad();
     }
 
@@ -59,15 +60,13 @@ public class GpxTravelTimeConsistencyTest {
         GHPoint routeStart = new GHPoint(43.727687, 7.418737);
         GHPoint routeEnd = new GHPoint(43.74958, 7.436566);
         GHRequest request = new GHRequest(routeStart, routeEnd);
-        request.setWeighting("fastest");
-        request.setVehicle("foot");
+        request.setProfile("profile");
         PathWrapper path = hopper.route(request).getBest();
         List<GPXEntry> gpxList = GpxFromInstructions.createGPXList(path.getInstructions());
-        for(GPXEntry entry : gpxList) {
-            if (entry.getTime() != null ) {
+        for (GPXEntry entry : gpxList) {
+            if (entry.getTime() != null) {
                 GHRequest requestForWaypoint = new GHRequest(routeStart, entry.getPoint());
-                requestForWaypoint.setWeighting("fastest");
-                requestForWaypoint.setVehicle("foot");
+                requestForWaypoint.setProfile("profile");
                 PathWrapper partialPath = hopper.route(requestForWaypoint).getBest();
                 assertEquals("GPXListEntry timeStamp is expected to be the same as route duration.", partialPath.getTime(), entry.getTime().longValue());
             }
diff --git a/web/src/test/java/com/graphhopper/http/resources/GtfsTest.java b/web/src/test/java/com/graphhopper/http/resources/GtfsTest.java
index 441b3b5b5..22b363226 100644
--- a/web/src/test/java/com/graphhopper/http/resources/GtfsTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/GtfsTest.java
@@ -18,19 +18,23 @@
 package com.graphhopper.http.resources;
 
 import com.graphhopper.GHResponse;
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.GraphHopperApplication;
 import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
 import com.graphhopper.resources.InfoResource;
 import com.graphhopper.util.Helper;
 import io.dropwizard.testing.junit.DropwizardAppRule;
-import java.io.File;
-import javax.ws.rs.core.Response;
 import org.junit.AfterClass;
-import static org.junit.Assert.*;
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Test;
+
+import javax.ws.rs.core.Response;
+import java.io.File;
+import java.util.Collections;
+
 import static com.graphhopper.http.util.TestUtils.clientTarget;
+import static org.junit.Assert.*;
 
 /**
  * Similar to PtRouteResourceTest, but tests the entire app, not the resource, so that the plugging-together
@@ -46,7 +50,8 @@ public class GtfsTest {
                 putObject("graph.flag_encoders", "foot").
                 putObject("datareader.file", "../reader-gtfs/files/beatty.osm").
                 putObject("gtfs.file", "../reader-gtfs/files/sample-feed.zip").
-                putObject("graph.location", DIR);
+                putObject("graph.location", DIR).
+                setProfiles(Collections.singletonList(new ProfileConfig("profile").setVehicle("foot").setWeighting("fastest")));
     }
 
     @ClassRule
diff --git a/web/src/test/java/com/graphhopper/http/resources/I18nResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/I18nResourceTest.java
index 72dcc1c07..7f5fcf521 100644
--- a/web/src/test/java/com/graphhopper/http/resources/I18nResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/I18nResourceTest.java
@@ -1,5 +1,6 @@
 package com.graphhopper.http.resources;
 
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.GraphHopperApplication;
 import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
 import com.graphhopper.util.Helper;
@@ -10,10 +11,11 @@ import org.junit.Test;
 
 import javax.ws.rs.core.Response;
 import java.io.File;
+import java.util.Collections;
 
+import static com.graphhopper.http.util.TestUtils.clientTarget;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static com.graphhopper.http.util.TestUtils.clientTarget;
 
 public class I18nResourceTest {
     private static final String DIR = "./target/andorra-gh/";
@@ -24,7 +26,8 @@ public class I18nResourceTest {
         config.getGraphHopperConfiguration().
                 putObject("graph.flag_encoders", "car").
                 putObject("datareader.file", "../core/files/andorra.osm.pbf").
-                putObject("graph.location", DIR);
+                putObject("graph.location", DIR).
+                setProfiles(Collections.singletonList(new ProfileConfig("car").setVehicle("car").setWeighting("fastest")));
     }
 
     @ClassRule
diff --git a/web/src/test/java/com/graphhopper/http/resources/IsochroneResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/IsochroneResourceTest.java
index d8ad33444..86f0feb24 100644
--- a/web/src/test/java/com/graphhopper/http/resources/IsochroneResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/IsochroneResourceTest.java
@@ -19,9 +19,9 @@
 package com.graphhopper.http.resources;
 
 import com.fasterxml.jackson.databind.JsonNode;
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.GraphHopperApplication;
 import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
-import static com.graphhopper.http.util.TestUtils.clientTarget;
 import com.graphhopper.json.geo.JsonFeatureCollection;
 import com.graphhopper.util.Helper;
 import io.dropwizard.testing.junit.DropwizardAppRule;
@@ -34,7 +34,9 @@ import org.locationtech.jts.geom.GeometryFactory;
 
 import javax.ws.rs.core.Response;
 import java.io.File;
+import java.util.Arrays;
 
+import static com.graphhopper.http.util.TestUtils.clientTarget;
 import static com.graphhopper.util.Parameters.Routing.BLOCK_AREA;
 import static junit.framework.TestCase.assertFalse;
 import static junit.framework.TestCase.assertTrue;
@@ -49,7 +51,11 @@ public class IsochroneResourceTest {
         config.getGraphHopperConfiguration().
                 putObject("graph.flag_encoders", "car").
                 putObject("datareader.file", "../core/files/andorra.osm.pbf").
-                putObject("graph.location", DIR);
+                putObject("graph.location", DIR).
+                setProfiles(Arrays.asList(
+                        new ProfileConfig("fast_car").setVehicle("car").setWeighting("fastest"),
+                        new ProfileConfig("short_car").setVehicle("car").setWeighting("shortest")
+                ));
     }
 
     @ClassRule
@@ -66,6 +72,7 @@ public class IsochroneResourceTest {
     @Test
     public void requestByTimeLimit() {
         Response rsp = clientTarget(app, "/isochrone")
+                .queryParam("weighting", "fastest")
                 .queryParam("point", "42.531073,1.573792")
                 .queryParam("time_limit", 5 * 60)
                 .queryParam("buckets", 2)
@@ -87,6 +94,7 @@ public class IsochroneResourceTest {
     @Test
     public void requestByDistanceLimit() {
         Response rsp = clientTarget(app, "/isochrone")
+                .queryParam("weighting", "fastest")
                 .queryParam("point", "42.531073,1.573792")
                 .queryParam("distance_limit", 3_000)
                 .queryParam("buckets", 2)
@@ -108,6 +116,7 @@ public class IsochroneResourceTest {
     @Test
     public void requestReverseFlow() {
         Response rsp = clientTarget(app, "/isochrone")
+                .queryParam("weighting", "fastest")
                 .queryParam("point", "42.531073,1.573792")
                 .queryParam("reverse_flow", true)
                 .queryParam("time_limit", 5 * 60)
@@ -132,7 +141,7 @@ public class IsochroneResourceTest {
 
     @Test
     public void requestBadRequest() {
-        Response response = clientTarget(app, "/route?point=-1.816719,51.557148").request().buildGet().invoke();
+        Response response = clientTarget(app, "/route?weighting=fastest&point=-1.816719,51.557148").request().buildGet().invoke();
         assertEquals(400, response.getStatus());
     }
 
@@ -170,7 +179,7 @@ public class IsochroneResourceTest {
 
     @Test
     public void requestJsonBadType() {
-        Response response = clientTarget(app, "/isochrone?point=42.531073,1.573792&time_limit=130&type=xml")
+        Response response = clientTarget(app, "/isochrone?weighting=fastest&point=42.531073,1.573792&time_limit=130&type=xml")
                 .request().buildGet().invoke();
 
         JsonNode json = response.readEntity(JsonNode.class);
@@ -182,6 +191,7 @@ public class IsochroneResourceTest {
     @Test
     public void requestWithBlockArea() {
         Response rsp = clientTarget(app, "/isochrone")
+                .queryParam("weighting", "fastest")
                 .queryParam("point", "42.531073,1.573792")
                 .queryParam("time_limit", 5 * 60)
                 .queryParam("buckets", 2)
@@ -205,7 +215,7 @@ public class IsochroneResourceTest {
 
     @Test
     public void requestJsonWithType() {
-        Response response = clientTarget(app, "/isochrone?point=42.531073,1.573792&time_limit=130&type=json")
+        Response response = clientTarget(app, "/isochrone?weighting=fastest&point=42.531073,1.573792&time_limit=130&type=json")
                 .request().buildGet().invoke();
         JsonNode json = response.readEntity(JsonNode.class);
         assertTrue(json.has("polygons"));
@@ -214,7 +224,7 @@ public class IsochroneResourceTest {
 
     @Test
     public void requestJsonNoType() {
-        Response response = clientTarget(app, "/isochrone?point=42.531073,1.573792&time_limit=130")
+        Response response = clientTarget(app, "/isochrone?weighting=fastest&point=42.531073,1.573792&time_limit=130")
                 .request().buildGet().invoke();
         JsonNode json = response.readEntity(JsonNode.class);
         assertTrue(json.has("polygons"));
@@ -223,7 +233,7 @@ public class IsochroneResourceTest {
 
     @Test
     public void requestGeoJsonPolygons() {
-        Response response = clientTarget(app, "/isochrone?point=42.531073,1.573792&time_limit=130&type=geojson")
+        Response response = clientTarget(app, "/isochrone?weighting=fastest&point=42.531073,1.573792&time_limit=130&type=geojson")
                 .request().buildGet().invoke();
         JsonNode json = response.readEntity(JsonNode.class);
 
@@ -247,7 +257,7 @@ public class IsochroneResourceTest {
 
     @Test
     public void requestGeoJsonPolygonsBuckets() {
-        Response response = clientTarget(app, "/isochrone?point=42.531073,1.573792&time_limit=130&type=geojson&buckets=3")
+        Response response = clientTarget(app, "/isochrone?weighting=fastest&point=42.531073,1.573792&time_limit=130&type=geojson&buckets=3")
                 .request().buildGet().invoke();
         JsonNode json = response.readEntity(JsonNode.class);
 
diff --git a/web/src/test/java/com/graphhopper/http/resources/MvtResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/MvtResourceTest.java
index 9884da15c..0418229f4 100644
--- a/web/src/test/java/com/graphhopper/http/resources/MvtResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/MvtResourceTest.java
@@ -17,6 +17,7 @@
  */
 package com.graphhopper.http.resources;
 
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.GraphHopperApplication;
 import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
 import com.graphhopper.util.Helper;
@@ -37,12 +38,13 @@ import javax.ws.rs.core.Response;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
+import static com.graphhopper.http.util.TestUtils.clientTarget;
 import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assert.assertEquals;
-import static com.graphhopper.http.util.TestUtils.clientTarget;
 
 /**
  * @author Peter Karich
@@ -59,7 +61,8 @@ public class MvtResourceTest {
                 putObject("prepare.min_network_size", 0).
                 putObject("prepare.min_one_way_network_size", 0).
                 putObject("datareader.file", "../core/files/andorra.osm.pbf").
-                putObject("graph.location", DIR);
+                putObject("graph.location", DIR).
+                setProfiles(Collections.singletonList(new ProfileConfig("car").setVehicle("car").setWeighting("fastest")));
     }
 
     @ClassRule
diff --git a/web/src/test/java/com/graphhopper/http/resources/NearestResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/NearestResourceTest.java
index 7db21a7fb..276c47642 100644
--- a/web/src/test/java/com/graphhopper/http/resources/NearestResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/NearestResourceTest.java
@@ -17,6 +17,7 @@
  */
 package com.graphhopper.http.resources;
 
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.GraphHopperApplication;
 import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
 import com.graphhopper.resources.NearestResource;
@@ -28,10 +29,11 @@ import org.junit.Test;
 
 import javax.ws.rs.core.Response;
 import java.io.File;
+import java.util.Collections;
 
+import static com.graphhopper.http.util.TestUtils.clientTarget;
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertThat;
-import static com.graphhopper.http.util.TestUtils.clientTarget;
 
 /**
  * @author svantulden
@@ -45,7 +47,8 @@ public class NearestResourceTest {
         config.getGraphHopperConfiguration().
                 putObject("graph.flag_encoders", "car").
                 putObject("datareader.file", "../core/files/andorra.osm.pbf").
-                putObject("graph.location", dir);
+                putObject("graph.location", dir).
+                setProfiles(Collections.singletonList(new ProfileConfig("car").setVehicle("car").setWeighting("fastest")));
     }
 
     @ClassRule
@@ -59,7 +62,7 @@ public class NearestResourceTest {
     }
 
     @Test
-    public void testBasicNearestQuery() throws Exception {
+    public void testBasicNearestQuery() {
         final Response response = clientTarget(app, "/nearest?point=42.554851,1.536198").request().buildGet().invoke();
         assertThat("HTTP status", response.getStatus(), is(200));
         NearestResource.Response json = response.readEntity(NearestResource.Response.class);
diff --git a/web/src/test/java/com/graphhopper/http/resources/NearestResourceWithEleTest.java b/web/src/test/java/com/graphhopper/http/resources/NearestResourceWithEleTest.java
index fbc842d30..d17e857f2 100644
--- a/web/src/test/java/com/graphhopper/http/resources/NearestResourceWithEleTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/NearestResourceWithEleTest.java
@@ -19,6 +19,7 @@ package com.graphhopper.http.resources;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.GraphHopperApplication;
 import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
 import com.graphhopper.util.Helper;
@@ -28,10 +29,11 @@ import org.junit.ClassRule;
 import org.junit.Test;
 
 import java.io.File;
+import java.util.Collections;
 
+import static com.graphhopper.http.util.TestUtils.clientTarget;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static com.graphhopper.http.util.TestUtils.clientTarget;
 
 /**
  * @author svantulden
@@ -48,7 +50,8 @@ public class NearestResourceWithEleTest {
                 putObject("prepare.min_one_way_network_size", 0).
                 putObject("graph.flag_encoders", "car").
                 putObject("datareader.file", "../core/files/monaco.osm.gz").
-                putObject("graph.location", dir);
+                putObject("graph.location", dir).
+                setProfiles(Collections.singletonList(new ProfileConfig("car").setVehicle("car").setWeighting("fastest")));
     }
 
     @ClassRule
diff --git a/web/src/test/java/com/graphhopper/http/resources/PtIsochroneTest.java b/web/src/test/java/com/graphhopper/http/resources/PtIsochroneTest.java
index 7719cc27f..5ddf927a2 100644
--- a/web/src/test/java/com/graphhopper/http/resources/PtIsochroneTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/PtIsochroneTest.java
@@ -18,6 +18,7 @@
 
 package com.graphhopper.http.resources;
 
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.GraphHopperApplication;
 import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
 import com.graphhopper.resources.PtIsochroneResource;
@@ -36,10 +37,11 @@ import javax.ws.rs.client.WebTarget;
 import java.io.File;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
+import java.util.Collections;
 
+import static com.graphhopper.http.util.TestUtils.clientTarget;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static com.graphhopper.http.util.TestUtils.clientTarget;
 
 public class PtIsochroneTest {
 
@@ -53,7 +55,8 @@ public class PtIsochroneTest {
         config.getGraphHopperConfiguration()
                 .putObject("graph.flag_encoders", "foot")
                 .putObject("graph.location", GRAPH_LOC)
-                .putObject("gtfs.file", "../reader-gtfs/files/sample-feed.zip");
+                .putObject("gtfs.file", "../reader-gtfs/files/sample-feed.zip").
+                setProfiles(Collections.singletonList(new ProfileConfig("foot").setVehicle("foot").setWeighting("fastest")));
         Helper.removeDir(new File(GRAPH_LOC));
     }
 
diff --git a/web/src/test/java/com/graphhopper/http/resources/RouteResourceIssue1574Test.java b/web/src/test/java/com/graphhopper/http/resources/RouteResourceIssue1574Test.java
index 2fd5d8c40..d105b0853 100644
--- a/web/src/test/java/com/graphhopper/http/resources/RouteResourceIssue1574Test.java
+++ b/web/src/test/java/com/graphhopper/http/resources/RouteResourceIssue1574Test.java
@@ -22,7 +22,6 @@ import com.graphhopper.config.CHProfileConfig;
 import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.GraphHopperApplication;
 import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
-import static com.graphhopper.http.util.TestUtils.clientTarget;
 import com.graphhopper.util.Helper;
 import io.dropwizard.testing.junit.DropwizardAppRule;
 import org.junit.AfterClass;
@@ -34,6 +33,7 @@ import javax.ws.rs.core.Response;
 import java.io.File;
 import java.util.Collections;
 
+import static com.graphhopper.http.util.TestUtils.clientTarget;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 
@@ -72,7 +72,7 @@ public class RouteResourceIssue1574Test {
 
     @Test
     public void testStallOnDemandBug_issue1574() {
-        final Response response = clientTarget(app, "/route?point=42.486984,1.493152&point=42.481863,1.491297&point=42.49697,1.501265&&vehicle=car&weighting=fastest&stall_on_demand=true").request().buildGet().invoke();
+        final Response response = clientTarget(app, "/route?point=42.486984,1.493152&point=42.481863,1.491297&point=42.49697,1.501265&vehicle=car&weighting=fastest&stall_on_demand=true").request().buildGet().invoke();
         JsonNode json = response.readEntity(JsonNode.class);
         assertFalse("there should be no error, but: " + json.get("message"), json.has("message"));
         System.out.println(json);
diff --git a/web/src/test/java/com/graphhopper/http/resources/RouteResourceProfileSelectionTest.java b/web/src/test/java/com/graphhopper/http/resources/RouteResourceProfileSelectionTest.java
index 00727ea91..cfd6c5ff9 100644
--- a/web/src/test/java/com/graphhopper/http/resources/RouteResourceProfileSelectionTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/RouteResourceProfileSelectionTest.java
@@ -82,25 +82,21 @@ public class RouteResourceProfileSelectionTest {
 
     @ParameterizedTest
     @ValueSource(strings = {"CH", "LM", "flex"})
-    public void defaultVehicle(String mode) {
+    public void missingVehicleOrWeighting(String mode) {
         assertDistance("car", "fastest", mode, 3563);
         assertDistance("foot", "shortest", mode, 2935);
         assertDistance("bike", "short_fastest", mode, 3085);
-        // for bike we can skip the vehicle here, because its the first of the encoders
+        // we can also skip the vehicles, because the weighting is enough to distinguish a single profile
+        assertDistance(null, "fastest", mode, 3563);
+        assertDistance(null, "shortest", mode, 2935);
         assertDistance(null, "short_fastest", mode, 3085);
-    }
-
-    @ParameterizedTest
-    @ValueSource(strings = {"CH", "LM", "flex"})
-    public void noWeighting(String mode) {
-        // for car this works fine as the default weighting is fastest and we fall back to this
+        // the same goes for the weighting
         assertDistance("car", null, mode, 3563);
-        // for foot and bike this does not work except for CH, because we get the wrong weighting (they are not using fastest)
-        // todo: this situation will be improved once we fully make use of profiles
-        if (mode.equals("CH")) {
-            assertDistance("foot", null, mode, 2935);
-            assertDistance("bike", null, mode, 3085);
-        }
+        assertDistance("foot", null, mode, 2935);
+        assertDistance("bike", null, mode, 3085);
+        // not giving any information does not work however, because all three profiles match
+        assertError((String) null, null, mode, "multiple", "profiles matching your request");
+
     }
 
     private void assertDistance(String vehicle, String weighting, String mode, double expectedDistance) {
@@ -108,6 +104,11 @@ public class RouteResourceProfileSelectionTest {
         assertDistance(doPost(vehicle, weighting, mode), expectedDistance);
     }
 
+    private void assertError(String vehicle, String weighting, String mode, String... expectedErrors) {
+        assertError(doGet(vehicle, weighting, mode), expectedErrors);
+        assertError(doPost(vehicle, weighting, mode), expectedErrors);
+    }
+
     private Response doGet(String vehicle, String weighting, String mode) {
         String urlParams = "point=43.727879,7.409678&point=43.745987,7.429848";
         if (vehicle != null)
@@ -146,6 +147,8 @@ public class RouteResourceProfileSelectionTest {
     }
 
     private void assertError(Response response, String... expectedErrors) {
+        if (expectedErrors.length == 0)
+            throw new IllegalArgumentException("there should be at least one expected error");
         JsonNode json = response.readEntity(JsonNode.class);
         assertEquals(400, response.getStatus(), "there should have been an error containing: " + Arrays.toString(expectedErrors));
         assertTrue(json.has("message"));
diff --git a/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java
index 86dd9b240..a0bc003ef 100644
--- a/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java
@@ -50,9 +50,9 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
-import static org.junit.Assert.*;
 import static com.graphhopper.http.util.TestUtils.clientTarget;
 import static com.graphhopper.http.util.TestUtils.clientUrl;
+import static org.junit.Assert.*;
 
 /**
  * @author Peter Karich
@@ -72,8 +72,7 @@ public class RouteResourceTest {
                 putObject("graph.encoded_values", "road_class,surface,road_environment,max_speed").
                 putObject("graph.location", DIR)
                 .setProfiles(Collections.singletonList(new ProfileConfig("my_car").setVehicle("car").setWeighting("fastest")))
-                .setCHProfiles(Collections.singletonList(new CHProfileConfig("my_car"))
-                );
+                .setCHProfiles(Collections.singletonList(new CHProfileConfig("my_car")));
     }
 
     @ClassRule
diff --git a/web/src/test/java/com/graphhopper/http/resources/RouteResourceTurnCostsTest.java b/web/src/test/java/com/graphhopper/http/resources/RouteResourceTurnCostsTest.java
new file mode 100644
index 000000000..85b33bd45
--- /dev/null
+++ b/web/src/test/java/com/graphhopper/http/resources/RouteResourceTurnCostsTest.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to GraphHopper GmbH under one or more contributor
+ *  license agreements. See the NOTICE file distributed with this work for
+ *  additional information regarding copyright ownership.
+ *
+ *  GraphHopper GmbH licenses this file to you under the Apache License,
+ *  Version 2.0 (the "License"); you may not use this file except in
+ *  compliance with the License. You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package com.graphhopper.http.resources;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.graphhopper.config.CHProfileConfig;
+import com.graphhopper.config.LMProfileConfig;
+import com.graphhopper.config.ProfileConfig;
+import com.graphhopper.http.GraphHopperApplication;
+import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
+import com.graphhopper.util.Helper;
+import io.dropwizard.testing.junit5.DropwizardAppExtension;
+import io.dropwizard.testing.junit5.DropwizardExtensionsSupport;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import javax.ws.rs.core.Response;
+import java.io.File;
+import java.util.Arrays;
+
+import static com.graphhopper.http.util.TestUtils.clientTarget;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+@ExtendWith(DropwizardExtensionsSupport.class)
+public class RouteResourceTurnCostsTest {
+
+    private static final String DIR = "./target/route-resource-turn-costs-gh/";
+    private DropwizardAppExtension<GraphHopperServerTestConfiguration> app = new DropwizardAppExtension(GraphHopperApplication.class, createConfig());
+
+    private static GraphHopperServerTestConfiguration createConfig() {
+        GraphHopperServerTestConfiguration config = new GraphHopperServerTestConfiguration();
+        config.getGraphHopperConfiguration().
+                putObject("graph.flag_encoders", "car|turn_costs=true").
+                putObject("routing.ch.disabling_allowed", true).
+                putObject("prepare.min_network_size", 0).
+                putObject("prepare.min_one_way_network_size", 0).
+                putObject("datareader.file", "../core/files/moscow.osm.gz").
+                putObject("graph.encoded_values", "road_class,surface,road_environment,max_speed").
+                putObject("graph.location", DIR)
+                .setProfiles(Arrays.asList(
+                        new ProfileConfig("my_car_turn_costs").setVehicle("car").setWeighting("fastest").setTurnCosts(true),
+                        new ProfileConfig("my_car_no_turn_costs").setVehicle("car").setWeighting("fastest").setTurnCosts(false)
+                ))
+                .setCHProfiles(Arrays.asList(
+                        new CHProfileConfig("my_car_turn_costs"),
+                        new CHProfileConfig("my_car_no_turn_costs")
+                ))
+                .setLMProfiles(Arrays.asList(
+                        new LMProfileConfig("my_car_turn_costs"),
+                        new LMProfileConfig("my_car_no_turn_costs")
+                ));
+        return config;
+    }
+
+    @BeforeAll
+    @AfterAll
+    public static void cleanUp() {
+        Helper.removeDir(new File(DIR));
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = {
+            "",
+            "&ch.disable=true",
+            "&ch.disable=true&lm.disable=true"})
+    public void getQuery_canToggleTurnCostsOnOff(String hints) {
+        String pointsStr = "point=55.813357,37.5958585&point=55.811042,37.594689";
+
+        assertDistanceGet(pointsStr + hints, 1044);
+        assertDistanceGet(pointsStr + "&edge_based=true" + hints, 1044);
+        assertDistanceGet(pointsStr + "&turn_costs=true" + hints, 1044);
+        assertDistanceGet(pointsStr + "&edge_based=false" + hints, 400);
+        assertDistanceGet(pointsStr + "&turn_costs=false" + hints, 400);
+    }
+
+    private void assertDistanceGet(String urlParams, double expectedDistance) {
+        final Response response = clientTarget(app, "/route?" + urlParams).request().buildGet().invoke();
+        assertEquals(200, response.getStatus());
+        JsonNode json = response.readEntity(JsonNode.class);
+        JsonNode infoJson = json.get("info");
+        assertFalse(infoJson.has("errors"));
+        JsonNode path = json.get("paths").get(0);
+        double distance = path.get("distance").asDouble();
+        assertEquals(expectedDistance, distance, 1);
+    }
+}
diff --git a/web/src/test/java/com/graphhopper/http/resources/RouteResourceWithEleTest.java b/web/src/test/java/com/graphhopper/http/resources/RouteResourceWithEleTest.java
index bc106cf3e..b3a10ac24 100644
--- a/web/src/test/java/com/graphhopper/http/resources/RouteResourceWithEleTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/RouteResourceWithEleTest.java
@@ -18,9 +18,9 @@
 package com.graphhopper.http.resources;
 
 import com.fasterxml.jackson.databind.JsonNode;
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.GraphHopperApplication;
 import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
-import static com.graphhopper.http.util.TestUtils.clientTarget;
 import com.graphhopper.util.Helper;
 import io.dropwizard.testing.junit.DropwizardAppRule;
 import org.junit.AfterClass;
@@ -29,7 +29,9 @@ import org.junit.Test;
 
 import javax.ws.rs.core.Response;
 import java.io.File;
+import java.util.Collections;
 
+import static com.graphhopper.http.util.TestUtils.clientTarget;
 import static org.junit.Assert.*;
 
 /**
@@ -47,12 +49,15 @@ public class RouteResourceWithEleTest {
                 putObject("prepare.min_one_way_network_size", 0).
                 putObject("graph.flag_encoders", "car").
                 putObject("datareader.file", "../core/files/monaco.osm.gz").
-                putObject("graph.location", dir);
+                putObject("graph.location", dir).
+                setProfiles(Collections.singletonList(
+                        new ProfileConfig("profile").setVehicle("car").setWeighting("fastest")
+                ));
+
     }
 
     @ClassRule
-    public static final DropwizardAppRule<GraphHopperServerTestConfiguration> app = new DropwizardAppRule(
-            GraphHopperApplication.class, config);
+    public static final DropwizardAppRule<GraphHopperServerTestConfiguration> app = new DropwizardAppRule(GraphHopperApplication.class, config);
 
 
     @AfterClass
@@ -61,7 +66,7 @@ public class RouteResourceWithEleTest {
     }
 
     @Test
-    public void testElevation() throws Exception {
+    public void testElevation() {
         final Response response = clientTarget(app, "/route?" + "point=43.730864,7.420771&point=43.727687,7.418737&points_encoded=false&elevation=true").request().buildGet().invoke();
         assertEquals(200, response.getStatus());
         JsonNode json = response.readEntity(JsonNode.class);
@@ -81,7 +86,7 @@ public class RouteResourceWithEleTest {
     }
 
     @Test
-    public void testNoElevation() throws Exception {
+    public void testNoElevation() {
         // default is elevation=false
         Response response = clientTarget(app, "/route?point=43.730864,7.420771&point=43.727687,7.418737&points_encoded=false").request().buildGet().invoke();
         assertEquals(200, response.getStatus());
diff --git a/web/src/test/java/com/graphhopper/http/resources/SPTResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/SPTResourceTest.java
index 14e67073c..0602cb456 100644
--- a/web/src/test/java/com/graphhopper/http/resources/SPTResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/SPTResourceTest.java
@@ -18,6 +18,7 @@
 
 package com.graphhopper.http.resources;
 
+import com.graphhopper.config.ProfileConfig;
 import com.graphhopper.http.GraphHopperApplication;
 import com.graphhopper.http.util.GraphHopperServerTestConfiguration;
 import com.graphhopper.util.Helper;
@@ -29,12 +30,13 @@ import org.junit.Test;
 import javax.ws.rs.core.Response;
 import java.io.File;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
+import static com.graphhopper.http.util.TestUtils.clientTarget;
 import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-import static com.graphhopper.http.util.TestUtils.clientTarget;
 
 
 public class SPTResourceTest {
@@ -47,7 +49,8 @@ public class SPTResourceTest {
                 putObject("graph.flag_encoders", "car").
                 putObject("graph.encoded_values", "max_speed,road_class").
                 putObject("datareader.file", "../core/files/andorra.osm.pbf").
-                putObject("graph.location", DIR);
+                putObject("graph.location", DIR).
+                setProfiles(Collections.singletonList(new ProfileConfig("car").setVehicle("car").setWeighting("fastest")));
     }
 
     @ClassRule