diff --git a/surface/model_openapiv3.go b/surface/model_openapiv3.go
index e110e56e..9ab71ab1 100644
--- a/surface/model_openapiv3.go
+++ b/surface/model_openapiv3.go
@@ -24,6 +24,8 @@ import (
 	openapiv3 "github.com/googleapis/gnostic/OpenAPIv3"
 )
 
+var knownTypes = map[string]bool{"string": true, "integer": true, "number": true, "boolean": true, "array": true, "object": true}
+
 // NewModelFromOpenAPIv3 builds a model of an API service for use in code generation.
 func NewModelFromOpenAPI3(document *openapiv3.Document) (*Model, error) {
 	return newOpenAPI3Builder().buildModel(document)
@@ -51,9 +53,30 @@ func (b *OpenAPI3Builder) buildModel(document *openapiv3.Document) (*Model, erro
 
 // build builds an API service description, preprocessing its types and methods for code generation.
 func (b *OpenAPI3Builder) build(document *openapiv3.Document) (err error) {
+	err = b.buildTypesFromComponents(document.Components)
+	if err != nil {
+		return err
+	}
+
+	// Collect service method descriptions from each PathItem.
+	if document.Paths != nil {
+		for _, pair := range document.Paths.Path {
+			b.buildMethodFromPathItem(pair.Name, pair.Value)
+		}
+	}
+	return err
+}
+
+// buildTypesFromComponents builds multiple service type description from the "Components" section
+// in the OpenAPI specification.
+func (b *OpenAPI3Builder) buildTypesFromComponents(components *openapiv3.Components) (err error) {
+	if components == nil {
+		return nil
+	}
+
 	// Collect service type descriptions from Components/Schemas.
-	if document.Components != nil && document.Components.Schemas != nil {
-		for _, pair := range document.Components.Schemas.AdditionalProperties {
+	if components.Schemas != nil {
+		for _, pair := range components.Schemas.AdditionalProperties {
 			t, err := b.buildTypeFromSchemaOrReference(pair.Name, pair.Value)
 			if err != nil {
 				return err
@@ -63,12 +86,38 @@ func (b *OpenAPI3Builder) build(document *openapiv3.Document) (err error) {
 			}
 		}
 	}
-	// Collect service method descriptions from each PathItem.
-	if document.Paths != nil {
-		for _, pair := range document.Paths.Path {
-			b.buildMethodFromPathItem(pair.Name, pair.Value)
+	// Collect service type descriptions from Components/Parameters.
+	if components.Parameters != nil {
+		for _, pair := range components.Parameters.AdditionalProperties {
+			parameters := []*openapiv3.ParameterOrReference{pair.Value}
+			_, err := b.buildTypeFromParameters(pair.Name, parameters, nil, true)
+			if err != nil {
+				return err
+			}
+		}
+	}
+	// Collect service type descriptions from Components/requestBodies
+	if components.RequestBodies != nil {
+		for _, pair := range components.RequestBodies.AdditionalProperties {
+			t, err := b.buildTypeFromRequestBody(pair.Name, pair.Value, nil)
+
+			if err != nil {
+				return err
+			}
+			if t != nil {
+				b.model.addType(t)
+			}
+		}
+	}
+	// Collect service type descriptions from Components/responses
+	if components.Responses != nil {
+		for _, pair := range components.Responses.AdditionalProperties {
+			namedResponseOrReference := []*openapiv3.NamedResponseOrReference{pair}
+			responses := &openapiv3.Responses{ResponseOrReference: namedResponseOrReference}
+			b.buildTypeFromResponses(pair.Name, responses, true)
 		}
 	}
+
 	return err
 }
 
@@ -86,13 +135,14 @@ func (b *OpenAPI3Builder) buildTypeFromSchemaOrReference(
 				// If the schema has properties, generate a struct.
 				t.Kind = TypeKind_STRUCT
 			}
-			for _, pair2 := range schema.Properties.AdditionalProperties {
-				if schema := pair2.Value; schema != nil {
-					var f Field
-					f.Name = pair2.Name
+			for _, pair := range schema.Properties.AdditionalProperties {
+				if schema := pair.Value; schema != nil {
+					f := &Field{
+						Name:      pair.Name,
+						Serialize: true,
+					}
 					f.Kind, f.Type, f.Format = b.typeForSchemaOrReference(schema)
-					f.Serialize = true
-					t.addField(&f)
+					t.addField(f)
 				}
 			}
 		}
@@ -135,18 +185,19 @@ func (b *OpenAPI3Builder) buildMethodFromPathItem(
 			op = pathItem.Trace
 		}
 		if op != nil {
-			var m Method
-			m.Operation = op.OperationId
-			m.Path = path
-			m.Method = method
-			m.Name = sanitizeOperationName(op.OperationId)
+			m := &Method{
+				Operation:   op.OperationId,
+				Path:        path,
+				Method:      method,
+				Name:        sanitizeOperationName(op.OperationId),
+				Description: op.Description,
+			}
 			if m.Name == "" {
 				m.Name = generateOperationName(method, path)
 			}
-			m.Description = op.Description
-			m.ParametersTypeName, err = b.buildTypeFromParameters(m.Name, op.Parameters, op.RequestBody)
-			m.ResponsesTypeName, err = b.buildTypeFromResponses(&m, m.Name, op.Responses)
-			b.model.addMethod(&m)
+			m.ParametersTypeName, err = b.buildTypeFromParameters(m.Name, op.Parameters, op.RequestBody, false)
+			m.ResponsesTypeName, err = b.buildTypeFromResponses(m.Name, op.Responses, false)
+			b.model.addMethod(m)
 		}
 	}
 	return err
@@ -156,15 +207,25 @@ func (b *OpenAPI3Builder) buildMethodFromPathItem(
 func (b *OpenAPI3Builder) buildTypeFromParameters(
 	name string,
 	parameters []*openapiv3.ParameterOrReference,
-	requestBody *openapiv3.RequestBodyOrReference) (typeName string, err error) {
-	t := &Type{}
-	t.Name = name + "Parameters"
-	t.Description = t.Name + " holds parameters to " + name
-	t.Kind = TypeKind_STRUCT
-	t.Fields = make([]*Field, 0)
+	requestBody *openapiv3.RequestBodyOrReference,
+	fromComponent bool) (typeName string, err error) {
+
+	pName := name + "Parameters"
+	t := &Type{
+		Name:        pName,
+		Kind:        TypeKind_STRUCT,
+		Fields:      make([]*Field, 0),
+		Description: pName + " holds parameters to " + name,
+	}
+
+	if fromComponent {
+		t.Name = name
+		t.Description = t.Name + " is a parameter"
+	}
 	for _, parametersItem := range parameters {
-		var f Field
-		f.Type = fmt.Sprintf("%+v", parametersItem)
+		f := Field{
+			Type: fmt.Sprintf("%+v", parametersItem),
+		}
 		parameter := parametersItem.GetParameter()
 		if parameter != nil {
 			switch parameter.In {
@@ -185,54 +246,96 @@ func (b *OpenAPI3Builder) buildTypeFromParameters(
 			}
 			f.Serialize = true
 			t.addField(&f)
+		} else if parameterRef := parametersItem.GetReference(); parameterRef != nil {
+			f.Type = typeForRef(parameterRef.GetXRef())
+			f.Name = strings.ToLower(f.Type)
+			f.Kind = FieldKind_REFERENCE
+			t.addField(&f)
 		}
 	}
+
+	_, err = b.buildTypeFromRequestBody(name, requestBody, t)
+
+	if len(t.Fields) > 0 {
+		b.model.addType(t)
+		return t.Name, err
+	}
+	return "", err
+}
+
+// buildTypeFromRequestBody builds a service type description from the request bodies of an OpenAPI
+// description. If tIn is not given, a new type is created. Otherwise tIn is used.
+func (b *OpenAPI3Builder) buildTypeFromRequestBody(name string, requestBody *openapiv3.RequestBodyOrReference, tIn *Type) (tOut *Type, err error) {
+	tOut = &Type{
+		Name: name,
+	}
+
+	if tIn != nil {
+		tOut = tIn
+	}
+
 	if requestBody != nil {
 		content := requestBody.GetRequestBody().GetContent()
+		f := &Field{
+			Position:  Position_BODY,
+			Serialize: true,
+		}
+
 		if content != nil {
-			for _, pair2 := range content.GetAdditionalProperties() {
-				if pair2.Name != "application/json" {
-					log.Printf("unimplemented: %q requestBody(%s)", name, pair2.Name)
+			for _, pair := range content.GetAdditionalProperties() {
+				if pair.Name != "application/json" {
+					log.Printf("unimplemented: %q requestBody(%s)", name, pair.Name)
 					continue
 				}
-				var f Field
-				f.Position = Position_BODY
-				f.Kind, f.Type, f.Format = b.typeForSchemaOrReference(pair2.GetValue().GetSchema())
+				f.Kind, f.Type, f.Format = b.typeForSchemaOrReference(pair.GetValue().GetSchema())
 				f.Name = strings.ToLower(f.Type) // use the schema name as the parameter name, since none is directly specified
-				f.Serialize = true
-				t.addField(&f)
+				tOut.addField(f)
 			}
+		} else if reference := requestBody.GetReference(); reference != nil {
+			schemaOrReference := openapiv3.SchemaOrReference{&openapiv3.SchemaOrReference_Reference{Reference: reference}}
+			f.Kind, f.Type, f.Format = b.typeForSchemaOrReference(&schemaOrReference)
+			f.Name = strings.ToLower(f.Type) // use the schema name as the parameter name, since none is directly specified
+			tOut.addField(f)
 		}
 	}
-	if len(t.Fields) > 0 {
-		b.model.addType(t)
-		return t.Name, err
-	}
-	return "", err
+
+	return tOut, err
 }
 
 // buildTypeFromResponses builds a service type description from the responses of an API method
 func (b *OpenAPI3Builder) buildTypeFromResponses(
-	m *Method,
 	name string,
-	responses *openapiv3.Responses) (typeName string, err error) {
-	t := &Type{}
-	t.Name = name + "Responses"
-	t.Description = t.Name + " holds responses of " + name
-	t.Kind = TypeKind_STRUCT
-	t.Fields = make([]*Field, 0)
+	responses *openapiv3.Responses,
+	fromComponent bool) (typeName string, err error) {
+
+	rName := name + "Responses"
+	t := &Type{
+		Name:        name + "Responses",
+		Kind:        TypeKind_STRUCT,
+		Fields:      make([]*Field, 0),
+		Description: rName + " holds responses of " + name,
+	}
+
+	if fromComponent {
+		t.Name = name
+		t.Description = t.Name + " is a response"
+	}
 
 	addResponse := func(name string, value *openapiv3.ResponseOrReference) {
-		var f Field
-		f.Name = name
-		f.Serialize = false
+		f := Field{
+			Name:      name,
+			Serialize: false,
+		}
 		response := value.GetResponse()
 		if response != nil && response.GetContent() != nil {
 			for _, pair2 := range response.GetContent().GetAdditionalProperties() {
 				f.Kind, f.Type, f.Format = b.typeForSchemaOrReference(pair2.GetValue().GetSchema())
-				f.Kind = FieldKind_REFERENCE
 				t.addField(&f)
 			}
+		} else if responseRef := value.GetReference(); responseRef != nil {
+			schemaOrReference := openapiv3.SchemaOrReference{&openapiv3.SchemaOrReference_Reference{Reference: responseRef}}
+			f.Kind, f.Type, f.Format = b.typeForSchemaOrReference(&schemaOrReference)
+			t.addField(&f)
 		}
 	}
 
@@ -256,7 +359,7 @@ func (b *OpenAPI3Builder) typeForSchemaOrReference(value *openapiv3.SchemaOrRefe
 		return b.typeForSchema(value.GetSchema())
 	}
 	if value.GetReference() != nil {
-		return FieldKind_SCALAR, typeForRef(value.GetReference().XRef), ""
+		return FieldKind_REFERENCE, typeForRef(value.GetReference().XRef), ""
 	}
 	return FieldKind_SCALAR, "todo", ""
 }
@@ -282,10 +385,9 @@ func (b *OpenAPI3Builder) typeForSchema(schema *openapiv3.Schema) (kind FieldKin
 					a := items.GetSchemaOrReference()
 					if a[0].GetReference().GetXRef() != "" {
 						return FieldKind_ARRAY, typeForRef(a[0].GetReference().GetXRef()), format
-					} else if a[0].GetSchema().Type == "string" {
-						return FieldKind_ARRAY, "string", format
-					} else if a[0].GetSchema().Type == "object" {
-						return FieldKind_ARRAY, "object", format
+					} else if knownTypes[a[0].GetSchema().Type] {
+						// The items of the array is one of the known types.
+						return FieldKind_ARRAY, a[0].GetSchema().Type, a[0].GetSchema().Format
 					}
 				}
 			}