diff --git a/deploy/chart/local-path-provisioner/templates/configmap.yaml b/deploy/chart/local-path-provisioner/templates/configmap.yaml
index 6ad117b6aef9ccbe1d594ddcdcb77fb52d08cde9..0f45cdab9bdc2f3d025bfb8798fc36a0cb0dbc3a 100644
--- a/deploy/chart/local-path-provisioner/templates/configmap.yaml
+++ b/deploy/chart/local-path-provisioner/templates/configmap.yaml
@@ -14,6 +14,9 @@ data:
     {{- with .Values.sharedFileSystemPath }}
     {{- $config = set $config "sharedFileSystemPath" . }}
     {{- end }}
+    {{- with .Values.multipleStorageClasses }}
+    {{- $config = set $config "sharedFileSystemPath" . }}
+    {{- end }}
     {{- $config | toPrettyJson | nindent 4 }}
   setup: |-
     {{- .Values.configmap.setup | nindent 4 }}
diff --git a/deploy/chart/local-path-provisioner/templates/storageclass.yaml b/deploy/chart/local-path-provisioner/templates/storageclass.yaml
index 7dc9b17829e834e48fafdd1b90ee6d5acf91bd47..70fe8c995e3e17b95b0375a91e0734bae3ce5bcf 100644
--- a/deploy/chart/local-path-provisioner/templates/storageclass.yaml
+++ b/deploy/chart/local-path-provisioner/templates/storageclass.yaml
@@ -1,15 +1,25 @@
-{{ if .Values.storageClass.create -}}
+{{- $storageClasses := list }}
+{{ if .Values.multipleStorageClasses }}
+{{ $storageClasses = .Values.multipleStorageClasses }}
+{{- else }}
+{{ $storageClasses = list .Values }}
+{{ end }}
+{{- $dot := . }}
+{{- range $values := $storageClasses }}
+{{ if $values.storageClass.create -}}
 apiVersion: storage.k8s.io/v1
 kind: StorageClass
 metadata:
-  name: {{ .Values.storageClass.name }}
+  name: {{ $values.storageClass.name }}
   labels:
-{{ include "local-path-provisioner.labels" . | indent 4 }}
+{{ include "local-path-provisioner.labels" $dot | indent 4 }}
   annotations:
-    storageclass.kubernetes.io/is-default-class: "{{ .Values.storageClass.defaultClass }}"
-    defaultVolumeType: "{{ .Values.storageClass.defaultVolumeType }}"
-provisioner: {{ template "local-path-provisioner.provisionerName" . }}
-volumeBindingMode: {{ .Values.storageClass.volumeBindingMode }}
-reclaimPolicy: {{ .Values.storageClass.reclaimPolicy }}
+    storageclass.kubernetes.io/is-default-class: "{{ $values.storageClass.defaultClass }}"
+    defaultVolumeType: "{{ $values.storageClass.defaultVolumeType }}"
+provisioner: {{ template "local-path-provisioner.provisionerName" $dot }}
+volumeBindingMode: {{ $values.storageClass.volumeBindingMode }}
+reclaimPolicy: {{ $values.storageClass.reclaimPolicy }}
 allowVolumeExpansion: true
 {{- end }}
+---
+{{- end }}
diff --git a/deploy/chart/local-path-provisioner/values.yaml b/deploy/chart/local-path-provisioner/values.yaml
index 277007535f9866fcbb829a2b2fb5fe90caca105d..5b3fb0b7589a4c1bd943a4676a07309ae3964760 100644
--- a/deploy/chart/local-path-provisioner/values.yaml
+++ b/deploy/chart/local-path-provisioner/values.yaml
@@ -73,6 +73,21 @@ nodePathMap:
 # If `sharedFileSystemPath` is used, then `nodePathMap` must be set to `[]`.
 # sharedFileSystemPath: ""
 
+# `multipleStorageClasses` allows the provisioner to manage multiple independent storage classes.
+# Each storage class must have a unique name, and contains the same fields as shown above for
+# a single storage class setup, EXCEPT for the provisionerName, which is the same for all
+# storage classes
+# multipleStorageClasses:
+# - storageClass:
+#     name: my-storage-class-name
+#     create: true
+#     defaultClass: false
+#     reclaimPolicy: Delete
+#   sharedFileSystemPath: ""
+#   ## OR
+#   # See above
+#   nodePathMap: {}
+    
 podAnnotations: {}
 
 podSecurityContext: {}
diff --git a/provisioner.go b/provisioner.go
index b226a2144cf70b7577e077aacbbcf127ec35811f..797df703c5f07c7db1c557470846955e6bfd526c 100644
--- a/provisioner.go
+++ b/provisioner.go
@@ -81,12 +81,22 @@ type NodePathMapData struct {
 	Paths []string `json:"paths,omitempty"`
 }
 
-type ConfigData struct {
+type StorageClassConfigData struct {
 	NodePathMap          []*NodePathMapData `json:"nodePathMap,omitempty"`
-	CmdTimeoutSeconds    int                `json:"cmdTimeoutSeconds,omitempty"`
 	SharedFileSystemPath string             `json:"sharedFileSystemPath,omitempty"`
-	SetupCommand         string             `json:"setupCommand,omitempty"`
-	TeardownCommand      string             `json:"teardownCommand,omitempty"`
+}
+
+type ConfigData struct {
+	CmdTimeoutSeconds int    `json:"cmdTimeoutSeconds,omitempty"`
+	SetupCommand      string `json:"setupCommand,omitempty"`
+	TeardownCommand   string `json:"teardownCommand,omitempty"`
+	StorageClassConfigData
+	StorageClassConfigs map[string]StorageClassConfigData `json:"storageClassConfigs"`
+}
+
+type StorageClassConfig struct {
+	NodePathMap          map[string]*NodePathMap
+	SharedFileSystemPath string
 }
 
 type NodePathMap struct {
@@ -94,11 +104,11 @@ type NodePathMap struct {
 }
 
 type Config struct {
-	NodePathMap          map[string]*NodePathMap
-	CmdTimeoutSeconds    int
-	SharedFileSystemPath string
-	SetupCommand         string
-	TeardownCommand      string
+	CmdTimeoutSeconds int
+	SetupCommand      string
+	TeardownCommand   string
+	StorageClassConfig
+	StorageClassConfigs map[string]StorageClassConfig
 }
 
 func NewProvisioner(ctx context.Context, kubeClient *clientset.Clientset,
@@ -177,7 +187,7 @@ func (p *LocalPathProvisioner) watchAndRefreshConfig() {
 	}()
 }
 
-func (p *LocalPathProvisioner) getPathOnNode(node string, requestedPath string) (string, error) {
+func (p *LocalPathProvisioner) getPathOnNode(node string, requestedPath string, c *StorageClassConfig) (string, error) {
 	p.configMutex.RLock()
 	defer p.configMutex.RUnlock()
 
@@ -185,8 +195,7 @@ func (p *LocalPathProvisioner) getPathOnNode(node string, requestedPath string)
 		return "", fmt.Errorf("no valid config available")
 	}
 
-	c := p.config
-	sharedFS, err := p.isSharedFilesystem()
+	sharedFS, err := p.isSharedFilesystem(c)
 	if err != nil {
 		return "", err
 	}
@@ -222,7 +231,7 @@ func (p *LocalPathProvisioner) getPathOnNode(node string, requestedPath string)
 	return path, nil
 }
 
-func (p *LocalPathProvisioner) isSharedFilesystem() (bool, error) {
+func (p *LocalPathProvisioner) isSharedFilesystem(c *StorageClassConfig) (bool, error) {
 	p.configMutex.RLock()
 	defer p.configMutex.RUnlock()
 
@@ -230,7 +239,6 @@ func (p *LocalPathProvisioner) isSharedFilesystem() (bool, error) {
 		return false, fmt.Errorf("no valid config available")
 	}
 
-	c := p.config
 	if (c.SharedFileSystemPath != "") && (len(c.NodePathMap) != 0) {
 		return false, fmt.Errorf("both nodePathMap and sharedFileSystemPath are defined. Please make sure only one is in use")
 	}
@@ -246,11 +254,30 @@ func (p *LocalPathProvisioner) isSharedFilesystem() (bool, error) {
 	return false, fmt.Errorf("both nodePathMap and sharedFileSystemPath are unconfigured")
 }
 
+func (p *LocalPathProvisioner) pickConfig(storageClassName string) (*StorageClassConfig, error) {
+	if len(p.config.StorageClassConfigs) == 0 {
+		return &p.config.StorageClassConfig, nil
+	}
+	cfg, ok := p.config.StorageClassConfigs[storageClassName]
+	if !ok {
+		return nil, fmt.Errorf("BUG: Got request for unexpected storage class %s", storageClassName)
+	}
+	return &cfg, nil
+}
+
 func (p *LocalPathProvisioner) Provision(ctx context.Context, opts pvController.ProvisionOptions) (*v1.PersistentVolume, pvController.ProvisioningState, error) {
+	cfg, err := p.pickConfig(opts.StorageClass.Name)
+	if err != nil {
+		return nil, pvController.ProvisioningFinished, err
+	}
+	return p.provisionFor(opts, cfg)
+}
+
+func (p *LocalPathProvisioner) provisionFor(opts pvController.ProvisionOptions, c *StorageClassConfig) (*v1.PersistentVolume, pvController.ProvisioningState, error) {
 	pvc := opts.PVC
 	node := opts.SelectedNode
 	storageClass := opts.StorageClass
-	sharedFS, err := p.isSharedFilesystem()
+	sharedFS, err := p.isSharedFilesystem(c)
 	if err != nil {
 		return nil, pvController.ProvisioningFinished, err
 	}
@@ -279,7 +306,7 @@ func (p *LocalPathProvisioner) Provision(ctx context.Context, opts pvController.
 			requestedPath = storageClass.Parameters["nodePath"]
 		}
 	}
-	basePath, err := p.getPathOnNode(nodeName, requestedPath)
+	basePath, err := p.getPathOnNode(nodeName, requestedPath, c)
 	if err != nil {
 		return nil, pvController.ProvisioningFinished, err
 	}
@@ -307,7 +334,7 @@ func (p *LocalPathProvisioner) Provision(ctx context.Context, opts pvController.
 		Mode:        *pvc.Spec.VolumeMode,
 		SizeInBytes: storage.Value(),
 		Node:        nodeName,
-	}); err != nil {
+	}, c); err != nil {
 		return nil, pvController.ProvisioningFinished, err
 	}
 
@@ -375,10 +402,19 @@ func (p *LocalPathProvisioner) Provision(ctx context.Context, opts pvController.
 }
 
 func (p *LocalPathProvisioner) Delete(ctx context.Context, pv *v1.PersistentVolume) (err error) {
+	cfg, err := p.pickConfig(pv.Spec.StorageClassName)
+	if err != nil {
+		return err
+	}
+	return p.deleteFor(pv, cfg)
+}
+
+func (p *LocalPathProvisioner) deleteFor(pv *v1.PersistentVolume, c *StorageClassConfig) (err error) {
 	defer func() {
 		err = errors.Wrapf(err, "failed to delete volume %v", pv.Name)
 	}()
-	path, node, err := p.getPathAndNodeForPV(pv)
+
+	path, node, err := p.getPathAndNodeForPV(pv, c)
 	if err != nil {
 		return err
 	}
@@ -401,7 +437,7 @@ func (p *LocalPathProvisioner) Delete(ctx context.Context, pv *v1.PersistentVolu
 			Mode:        *pv.Spec.VolumeMode,
 			SizeInBytes: storage.Value(),
 			Node:        node,
-		}); err != nil {
+		}, c); err != nil {
 			logrus.Infof("clean up volume %v failed: %v", pv.Name, err)
 			return err
 		}
@@ -411,7 +447,7 @@ func (p *LocalPathProvisioner) Delete(ctx context.Context, pv *v1.PersistentVolu
 	return nil
 }
 
-func (p *LocalPathProvisioner) getPathAndNodeForPV(pv *v1.PersistentVolume) (path, node string, err error) {
+func (p *LocalPathProvisioner) getPathAndNodeForPV(pv *v1.PersistentVolume, cfg *StorageClassConfig) (path, node string, err error) {
 	defer func() {
 		err = errors.Wrapf(err, "failed to delete volume %v", pv.Name)
 	}()
@@ -425,7 +461,7 @@ func (p *LocalPathProvisioner) getPathAndNodeForPV(pv *v1.PersistentVolume) (pat
 		return "", "", fmt.Errorf("no path set")
 	}
 
-	sharedFS, err := p.isSharedFilesystem()
+	sharedFS, err := p.isSharedFilesystem(cfg)
 	if err != nil {
 		return "", "", err
 	}
@@ -475,11 +511,11 @@ type volumeOptions struct {
 	Node        string
 }
 
-func (p *LocalPathProvisioner) createHelperPod(action ActionType, cmd []string, o volumeOptions) (err error) {
+func (p *LocalPathProvisioner) createHelperPod(action ActionType, cmd []string, o volumeOptions, cfg *StorageClassConfig) (err error) {
 	defer func() {
 		err = errors.Wrapf(err, "failed to %v volume %v", action, o.Name)
 	}()
-	sharedFS, err := p.isSharedFilesystem()
+	sharedFS, err := p.isSharedFilesystem(cfg)
 	if err != nil {
 		return err
 	}
@@ -667,13 +703,39 @@ func loadConfigFile(configFile string) (cfgData *ConfigData, err error) {
 }
 
 func canonicalizeConfig(data *ConfigData) (cfg *Config, err error) {
-	defer func() {
-		err = errors.Wrapf(err, "config canonicalization failed")
-	}()
 	cfg = &Config{}
-	cfg.SharedFileSystemPath = data.SharedFileSystemPath
+	if len(data.StorageClassConfigs) == 0 {
+		defaultConfig, err := canonicalizeStorageClassConfig(&data.StorageClassConfigData)
+		if err != nil {
+			return nil, err
+		}
+		cfg.StorageClassConfig = *defaultConfig
+	} else {
+		cfg.StorageClassConfigs = make(map[string]StorageClassConfig, len(data.StorageClassConfigs))
+		for name, classData := range data.StorageClassConfigs {
+			classCfg, err := canonicalizeStorageClassConfig(&classData)
+			if err != nil {
+				return nil, errors.Wrap(err, fmt.Sprintf("config for class %s is invalid", name))
+			}
+			cfg.StorageClassConfigs[name] = *classCfg
+		}
+	}
 	cfg.SetupCommand = data.SetupCommand
 	cfg.TeardownCommand = data.TeardownCommand
+	if data.CmdTimeoutSeconds > 0 {
+		cfg.CmdTimeoutSeconds = data.CmdTimeoutSeconds
+	} else {
+		cfg.CmdTimeoutSeconds = defaultCmdTimeoutSeconds
+	}
+	return cfg, nil
+}
+
+func canonicalizeStorageClassConfig(data *StorageClassConfigData) (cfg *StorageClassConfig, err error) {
+	defer func() {
+		err = errors.Wrapf(err, "StorageClass config canonicalization failed")
+	}()
+	cfg = &StorageClassConfig{}
+	cfg.SharedFileSystemPath = data.SharedFileSystemPath
 	cfg.NodePathMap = map[string]*NodePathMap{}
 	for _, n := range data.NodePathMap {
 		if cfg.NodePathMap[n.Node] != nil {
@@ -698,11 +760,6 @@ func canonicalizeConfig(data *ConfigData) (cfg *Config, err error) {
 			npMap.Paths[path] = struct{}{}
 		}
 	}
-	if data.CmdTimeoutSeconds > 0 {
-		cfg.CmdTimeoutSeconds = data.CmdTimeoutSeconds
-	} else {
-		cfg.CmdTimeoutSeconds = defaultCmdTimeoutSeconds
-	}
 
 	return cfg, nil
 }