Type checking is done either by the compiler (static type checking) or during the program execution (dynamic type checking). It ensures that the operands of an operator are of compatible types. Assume that you want to add an int and a float in Java. Those are obviously different types, but it's allowed because the int variable is coerced to a float, and a floating-point add is done. Coercion is just the automatic process when a variable is implicitly converted to a legal type by compiler-generated code, or the interpreter. Compatible types are types that are legal for an operator or is allowed to be coerced.
In a programming language where all of the bindings of variables to types are static, as in C, C++ or JAVA, then the type checking can almost always be done statically.
The advantage of static type checking over dynamic type checking is that errors can be detected earlier, which is less costly. It also allows more effective program execution, i.e faster and/or reduced memory use. The disadvantage is the reduced programmer flexibility.