The wikipedia page on Type System has a good quote about what a type is:
a tractable syntactic framework for classifying phrases according to the kinds of values they compute
So a C struct is a type and you don't need objects for types.
Basically types are a way to decide how values in your language can fit together in a sane way. You can see some of this looking at a few languages:
In C:
int x = 'a' + 13; // 110
char x = 'a' + 13); // 'n'
In Python
>>> 'a' + 13
TypeError: cannot concatenate 'str' and 'int' objects
In different cases both of these are reasonable. This brings up the strongly typed vs weakly typed distinction. In a strongly typed language, like Python, you can't turn one type into another. C is weakly typed, if you have an char and want to cast it to a FILE, it will let you, the following doesn't even make a warning in default gcc:
FILE m = (*(FILE*) 'a')
This doesn't mean that C has no types, just that going from one type to an unrelated type is possible in some situations. There's a continuum across languages.
Haskell is strongly typed, if a function takes certain types of arguments and you try to call it with different types it's not going to compile. (Per your question, Haskell isn't OO but certainly has types.)
factorial 0 = 1
factorial n = n * factorial (n - 1)
If you try to call factorial with a string: factorial ("HI") it won't work. Note that you didn't have to say that n was a number. The compiler figured it out. This is something called type inferrence. Strong typing doesn't mean you need to explicitly state the types. Some languages can ensure no type errors occur without the annotations of C and Java.
Notice how Haskell threw an error at compile time. That's the other useful distinction: Static vs Dynamic typing. Static typing catches errors at compile time. Dynamic typing catches them at run time. The python above caught the type error at run-time, so Python is dynamically typed (it's also strongly typed). Pascal, like Haskell, is strongly typed and statically typed