diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs
index 4356f930..e934adb9 100644
--- a/serde/src/ser/mod.rs
+++ b/serde/src/ser/mod.rs
@@ -1727,6 +1727,13 @@ pub trait SerializeStruct {
     where
         T: Serialize;
 
+    /// Indicate that a struct field has been skipped.
+    #[inline]
+    fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
+        let _ = key;
+        Ok(())
+    }
+
     /// Finish serializing a struct.
     fn end(self) -> Result<Self::Ok, Self::Error>;
 }
@@ -1772,6 +1779,13 @@ pub trait SerializeStructVariant {
     where
         T: Serialize;
 
+    /// Indicate that a struct variant field has been skipped.
+    #[inline]
+    fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
+        let _ = key;
+        Ok(())
+    }
+
     /// Finish serializing a struct variant.
     fn end(self) -> Result<Self::Ok, Self::Error>;
 }
diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs
index 5ab6d0a9..8f6f717b 100644
--- a/serde_derive/src/de.rs
+++ b/serde_derive/src/de.rs
@@ -1384,26 +1384,27 @@ fn deserialize_identifier(
         "field identifier"
     };
 
-    let visit_index = if is_variant {
-        let variant_indices = 0u32..;
-        let fallthrough_msg = format!("variant index 0 <= i < {}", fields.len());
-        let visit_index = quote! {
-            fn visit_u32<__E>(self, __value: u32) -> _serde::export::Result<Self::Value, __E>
-                where __E: _serde::de::Error
-            {
-                match __value {
-                    #(
-                        #variant_indices => _serde::export::Ok(#constructors),
-                    )*
-                    _ => _serde::export::Err(_serde::de::Error::invalid_value(
-                                _serde::de::Unexpected::Unsigned(__value as u64),
-                                &#fallthrough_msg))
-                }
-            }
-        };
-        Some(visit_index)
+    let index_expecting = if is_variant {
+        "variant"
     } else {
-        None
+        "field"
+    };
+
+    let variant_indices = 0u32..;
+    let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
+    let visit_index = quote! {
+        fn visit_u32<__E>(self, __value: u32) -> _serde::export::Result<Self::Value, __E>
+            where __E: _serde::de::Error
+        {
+            match __value {
+                #(
+                    #variant_indices => _serde::export::Ok(#constructors),
+                )*
+                _ => _serde::export::Err(_serde::de::Error::invalid_value(
+                            _serde::de::Unexpected::Unsigned(__value as u64),
+                            &#fallthrough_msg))
+            }
+        }
     };
 
     let bytes_to_str = if fallthrough.is_some() {
diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs
index 9be9bddc..9c3310be 100644
--- a/serde_derive/src/ser.rs
+++ b/serde_derive/src/ser.rs
@@ -242,6 +242,7 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
         params,
         false,
         quote!(_serde::ser::SerializeStruct::serialize_field),
+        quote!(_serde::ser::SerializeStruct::skip_field),
     );
 
     let type_name = cattrs.name().serialize_name();
@@ -707,15 +708,23 @@ fn serialize_struct_variant<'a>(
     fields: &[Field],
     name: &str,
 ) -> Fragment {
-    let method = match context {
+    let (method, skip_method) = match context {
         StructVariant::ExternallyTagged { .. } => {
-            quote!(_serde::ser::SerializeStructVariant::serialize_field)
+            (
+                quote!(_serde::ser::SerializeStructVariant::serialize_field),
+                quote!(_serde::ser::SerializeStructVariant::skip_field),
+            )
         }
         StructVariant::InternallyTagged { .. } |
-        StructVariant::Untagged => quote!(_serde::ser::SerializeStruct::serialize_field),
+        StructVariant::Untagged => {
+            (
+                quote!(_serde::ser::SerializeStruct::serialize_field),
+                quote!(_serde::ser::SerializeStruct::skip_field),
+            )
+        }
     };
 
-    let serialize_fields = serialize_struct_visitor(fields, params, true, method);
+    let serialize_fields = serialize_struct_visitor(fields, params, true, method, skip_method);
 
     let mut serialized_fields = fields
         .iter()
@@ -829,6 +838,7 @@ fn serialize_struct_visitor(
     params: &Parameters,
     is_enum: bool,
     func: Tokens,
+    skip_func: Tokens,
 ) -> Vec<Tokens> {
     fields
         .iter()
@@ -859,7 +869,15 @@ fn serialize_struct_visitor(
 
                 match skip {
                     None => ser,
-                    Some(skip) => quote!(if !#skip { #ser }),
+                    Some(skip) => {
+                        quote! {
+                            if !#skip {
+                                #ser
+                            } else {
+                                try!(#skip_func(&mut __serde_state, #key_expr));
+                            }
+                        }
+                    }
                 }
             },
         )
diff --git a/test_suite/tests/test_de.rs b/test_suite/tests/test_de.rs
index 9fbfed46..da7232a5 100644
--- a/test_suite/tests/test_de.rs
+++ b/test_suite/tests/test_de.rs
@@ -521,6 +521,15 @@ declare_tests! {
                 Token::I32(2),
             Token::MapEnd,
         ],
+        Struct { a: 1, b: 2, c: 0 } => &[
+            Token::Map { len: Some(3) },
+                Token::U32(0),
+                Token::I32(1),
+
+                Token::U32(1),
+                Token::I32(2),
+            Token::MapEnd,
+        ],
         Struct { a: 1, b: 2, c: 0 } => &[
             Token::Struct { name: "Struct", len: 3 },
                 Token::Str("a"),