diff --git a/config/crds/cluster_v1alpha1_cluster.yaml b/config/crds/cluster_v1alpha1_cluster.yaml
index d60fd49b431c..5d510f025c0f 100644
--- a/config/crds/cluster_v1alpha1_cluster.yaml
+++ b/config/crds/cluster_v1alpha1_cluster.yaml
@@ -56,6 +56,12 @@ spec:
                 value:
                   type: object
                 valueFrom:
+                  properties:
+                    machineClass:
+                      properties:
+                        provider:
+                          type: string
+                      type: object
                   type: object
               type: object
           required:
diff --git a/config/crds/cluster_v1alpha1_machine.yaml b/config/crds/cluster_v1alpha1_machine.yaml
index 937e44650193..ee1d3bed4347 100644
--- a/config/crds/cluster_v1alpha1_machine.yaml
+++ b/config/crds/cluster_v1alpha1_machine.yaml
@@ -33,6 +33,12 @@ spec:
                 value:
                   type: object
                 valueFrom:
+                  properties:
+                    machineClass:
+                      properties:
+                        provider:
+                          type: string
+                      type: object
                   type: object
               type: object
             taints:
diff --git a/config/crds/cluster_v1alpha1_machineclass.yaml b/config/crds/cluster_v1alpha1_machineclass.yaml
new file mode 100644
index 000000000000..c89ef40185b6
--- /dev/null
+++ b/config/crds/cluster_v1alpha1_machineclass.yaml
@@ -0,0 +1,33 @@
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  creationTimestamp: null
+  labels:
+    controller-tools.k8s.io: "1.0"
+  name: machineclasses.cluster.k8s.io
+spec:
+  group: cluster.k8s.io
+  names:
+    kind: MachineClass
+    plural: machineclasses
+  scope: Namespaced
+  validation:
+    openAPIV3Schema:
+      properties:
+        apiVersion:
+          type: string
+        kind:
+          type: string
+        metadata:
+          type: object
+        providerConfig:
+          type: object
+      required:
+      - providerConfig
+  version: v1alpha1
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
diff --git a/config/crds/cluster_v1alpha1_machinedeployment.yaml b/config/crds/cluster_v1alpha1_machinedeployment.yaml
index bc960441de90..3592e00414ac 100644
--- a/config/crds/cluster_v1alpha1_machinedeployment.yaml
+++ b/config/crds/cluster_v1alpha1_machinedeployment.yaml
@@ -65,6 +65,12 @@ spec:
                         value:
                           type: object
                         valueFrom:
+                          properties:
+                            machineClass:
+                              properties:
+                                provider:
+                                  type: string
+                              type: object
                           type: object
                       type: object
                     taints:
diff --git a/config/crds/cluster_v1alpha1_machineset.yaml b/config/crds/cluster_v1alpha1_machineset.yaml
index 04cd83584513..7522abc3cd65 100644
--- a/config/crds/cluster_v1alpha1_machineset.yaml
+++ b/config/crds/cluster_v1alpha1_machineset.yaml
@@ -47,6 +47,12 @@ spec:
                         value:
                           type: object
                         valueFrom:
+                          properties:
+                            machineClass:
+                              properties:
+                                provider:
+                                  type: string
+                              type: object
                           type: object
                       type: object
                     taints:
diff --git a/pkg/apis/cluster/v1alpha1/common_types.go b/pkg/apis/cluster/v1alpha1/common_types.go
index 8f9d36fc435d..32bb55f8c19c 100644
--- a/pkg/apis/cluster/v1alpha1/common_types.go
+++ b/pkg/apis/cluster/v1alpha1/common_types.go
@@ -16,7 +16,10 @@ limitations under the License.
 
 package v1alpha1
 
-import "k8s.io/apimachinery/pkg/runtime"
+import (
+	corev1 "k8s.io/api/core/v1"
+	runtime "k8s.io/apimachinery/pkg/runtime"
+)
 
 // ProviderConfig defines the configuration to use during node creation.
 type ProviderConfig struct {
@@ -39,5 +42,17 @@ type ProviderConfig struct {
 // ProviderConfigSource represents a source for the provider-specific
 // resource configuration.
 type ProviderConfigSource struct {
-	// TODO(roberthbailey): Fill these in later
+	// The machine class from which the provider config should be sourced.
+	// +optional
+	MachineClass *MachineClassRef `json:"machineClass,omitempty"`
+}
+
+// MachineClassRef is a reference to the MachineClass object. Controllers should find the right MachineClass using this reference.
+type MachineClassRef struct {
+	// +optional
+	*corev1.ObjectReference `json:",inline"`
+
+	// Provider is the name of the cloud-provider which MachineClass is intended for.
+	// +optional
+	Provider string `json:"provider,omitempty"`
 }
diff --git a/pkg/apis/cluster/v1alpha1/machineclass_types.go b/pkg/apis/cluster/v1alpha1/machineclass_types.go
new file mode 100644
index 000000000000..9e2b1abb2933
--- /dev/null
+++ b/pkg/apis/cluster/v1alpha1/machineclass_types.go
@@ -0,0 +1,64 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed 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 v1alpha1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+)
+
+// +genclient
+// +genclient:noStatus
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// MachineClass can be used to templatize and re-use provider configuration
+// across multiple Machines / MachineSets / MachineDeployments.
+// +k8s:openapi-gen=true
+// +resource:path=machineclasses
+type MachineClass struct {
+	metav1.TypeMeta `json:",inline"`
+	// +optional
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	// The total capacity available on this machine type (cpu/memory/disk).
+	//
+	// WARNING: It is up to the creator of the MachineClass to ensure that
+	// this field is consistent with the underlying machine that will
+	// be provisioned when this class is used, to inform higher level
+	// automation (e.g. the cluster autoscaler).
+	// TODO(hardikdr) Add allocatable field once requirements are clear from autoscaler-clusterapi // integration topic.
+	// Capacity corev1.ResourceList `json:"capacity"`
+
+	// How much capacity is actually allocatable on this machine.
+	// Must be equal to or less than the capacity, and when less
+	// indicates the resources reserved for system overhead.
+	//
+	// WARNING: It is up to the creator of the MachineClass to ensure that
+	// this field is consistent with the underlying machine that will
+	// be provisioned when this class is used, to inform higher level
+	// automation (e.g. the cluster autoscaler).
+	// TODO(hardikdr) Add allocatable field once requirements are clear from autoscaler-clusterapi // integration topic.
+	// Allocatable corev1.ResourceList `json:"allocatable"`
+
+	// Provider-specific configuration to use during node creation.
+	ProviderConfig runtime.RawExtension `json:"providerConfig"`
+
+	// TODO: should this use an api.ObjectReference to a 'MachineTemplate' instead?
+	// A link to the MachineTemplate that will be used to create provider
+	// specific configuration for Machines of this class.
+	// MachineTemplate corev1.ObjectReference `json:machineTemplate`
+}
diff --git a/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go
index 24c00b0cde03..73598a5475ec 100644
--- a/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go
@@ -194,6 +194,54 @@ func (in *Machine) DeepCopyObject() runtime.Object {
 	return nil
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MachineClass) DeepCopyInto(out *MachineClass) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.ProviderConfig.DeepCopyInto(&out.ProviderConfig)
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineClass.
+func (in *MachineClass) DeepCopy() *MachineClass {
+	if in == nil {
+		return nil
+	}
+	out := new(MachineClass)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *MachineClass) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MachineClassRef) DeepCopyInto(out *MachineClassRef) {
+	*out = *in
+	if in.ObjectReference != nil {
+		in, out := &in.ObjectReference, &out.ObjectReference
+		*out = new(v1.ObjectReference)
+		**out = **in
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineClassRef.
+func (in *MachineClassRef) DeepCopy() *MachineClassRef {
+	if in == nil {
+		return nil
+	}
+	out := new(MachineClassRef)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *MachineDeployment) DeepCopyInto(out *MachineDeployment) {
 	*out = *in
@@ -654,7 +702,7 @@ func (in *ProviderConfig) DeepCopyInto(out *ProviderConfig) {
 	if in.ValueFrom != nil {
 		in, out := &in.ValueFrom, &out.ValueFrom
 		*out = new(ProviderConfigSource)
-		**out = **in
+		(*in).DeepCopyInto(*out)
 	}
 	return
 }
@@ -672,6 +720,11 @@ func (in *ProviderConfig) DeepCopy() *ProviderConfig {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ProviderConfigSource) DeepCopyInto(out *ProviderConfigSource) {
 	*out = *in
+	if in.MachineClass != nil {
+		in, out := &in.MachineClass, &out.MachineClass
+		*out = new(MachineClassRef)
+		(*in).DeepCopyInto(*out)
+	}
 	return
 }
 
diff --git a/sample/machineclass.yaml b/sample/machineclass.yaml
new file mode 100644
index 000000000000..6cf45d4e2e6f
--- /dev/null
+++ b/sample/machineclass.yaml
@@ -0,0 +1,31 @@
+# Sample machine-class object
+apiVersion: "cluster.k8s.io/v1alpha1"
+kind: MachineClass
+metadata:
+  name: small
+  namespace: foo
+providerConfig:
+  apiVersion: "gceproviderconfig/v1alpha1"
+  kind: "GCEProviderConfig"
+  project: "$GCLOUD_PROJECT"
+  zone: "us-central1-f"
+  machineType: "n1-standard-2"
+  image: "projects/ubuntu-os-cloud/global/images/family/ubuntu-1604-lts"
+
+---
+
+# Sample machine object
+apiVersion: cluster.k8s.io/v1alpha1
+kind: Machine
+metadata:
+  name: test-machine 
+  namespace: foo
+  labels:
+    test-label: test-label 
+spec:
+  providerConfig:
+    valueFrom:
+      machineClass: 
+        provider: gcp
+        name: small
+        namespace: foo